Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ts/better api consumer #9861

Merged
merged 3 commits into from
Feb 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion lib/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"prop-types": "^15.6.2",
"react": "^16.8.3",
"semver": "^6.0.0",
"shallow-equal": "^1.1.0",
"store2": "^2.7.1",
"telejson": "^3.2.0",
"ts-dedent": "^1.1.1",
Expand Down
95 changes: 45 additions & 50 deletions lib/api/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import React, { ReactElement, Component, useContext, useEffect, useMemo, ReactNode } from 'react';
import memoize from 'memoizerific';
// @ts-ignore shallow-equal is not in DefinitelyTyped
import shallowEqualObjects from 'shallow-equal/objects';
import React, {
Component,
Fragment,
FunctionComponent,
ReactElement,
ReactNode,
useContext,
useEffect,
useMemo,
useRef,
} from 'react';

import {
STORIES_CONFIGURED,
Expand Down Expand Up @@ -115,16 +122,16 @@ interface Children {

type StatePartial = Partial<State>;

export type Props = Children & RouterData & ProviderData & DocsModeData;
export type ManagerProviderProps = Children & RouterData & ProviderData & DocsModeData;

class ManagerProvider extends Component<Props, State> {
class ManagerProvider extends Component<ManagerProviderProps, State> {
api: API;

modules: any[];

static displayName = 'Manager';

constructor(props: Props) {
constructor(props: ManagerProviderProps) {
super(props);
const {
provider,
Expand Down Expand Up @@ -211,7 +218,7 @@ class ManagerProvider extends Component<Props, State> {
this.api = api;
}

static getDerivedStateFromProps = (props: Props, state: State) => {
static getDerivedStateFromProps = (props: ManagerProviderProps, state: State) => {
if (state.path !== props.path) {
return {
...state,
Expand All @@ -234,7 +241,7 @@ class ManagerProvider extends Component<Props, State> {
});
}

shouldComponentUpdate(nextProps: Props, nextState: State) {
shouldComponentUpdate(nextProps: ManagerProviderProps, nextState: State) {
const prevState = this.state;
const prevProps = this.props;

Expand All @@ -254,57 +261,45 @@ class ManagerProvider extends Component<Props, State> {
api: this.api,
};

// @ts-ignore
const content: ReactNode = typeof children === 'function' ? children(value) : children;

return <ManagerContext.Provider value={value}>{content}</ManagerContext.Provider>;
return (
<ManagerContext.Provider value={value}>
<ManagerConsumer>{children}</ManagerConsumer>
</ManagerContext.Provider>
);
}
}

interface ConsumerProps<S, C> {
filter?: (combo: C) => S;
pure?: boolean;
children: (d: S | C) => ReactElement<any> | null;
interface ManagerConsumerProps<P = unknown> {
filter?: (combo: Combo) => P;
children: FunctionComponent<P> | ReactNode;
}

interface SubState {
[key: string]: any;
}
const defaultFilter = (c: Combo) => c;

class ManagerConsumer extends Component<ConsumerProps<SubState, Combo>> {
prevChildren?: ReactElement<any> | null;
function ManagerConsumer<P = Combo>({
// @ts-ignore
filter = defaultFilter,
children,
}: ManagerConsumerProps<P>): ReactElement {
const c = useContext(ManagerContext);
const renderer = useRef(children);
const filterer = useRef(filter);

prevData?: SubState;
if (typeof renderer.current !== 'function') {
return <Fragment>{renderer.current}</Fragment>;
}

dataMemory?: (combo: Combo) => SubState;
const data = filterer.current(c);

constructor(props: ConsumerProps<SubState, Combo>) {
super(props);
this.dataMemory = props.filter ? memoize(10)(props.filter) : null;
}
const l = useMemo(() => {
return [...Object.entries(data).reduce((acc, keyval) => acc.concat(keyval), [])];
}, [c.state]);

render() {
const { children, pure } = this.props;
return useMemo(() => {
const Child = renderer.current as FunctionComponent<P>;

return (
<ManagerContext.Consumer>
{d => {
const data = this.dataMemory ? this.dataMemory(d) : d;
if (
pure &&
this.prevChildren &&
this.prevData &&
shallowEqualObjects(data, this.prevData)
) {
return this.prevChildren;
}
this.prevChildren = children(data);
this.prevData = data;
return this.prevChildren;
}}
</ManagerContext.Consumer>
);
}
return <Child {...data} />;
}, l);
}

export function useStorybookState(): State {
Expand Down Expand Up @@ -359,7 +354,7 @@ export function useParameter<S>(parameterKey: string, defaultValue?: S) {
}

type StateMerger<S> = (input: S) => S;
// chache for taking care of HMR
// cache for taking care of HMR
const addonStateCache: {
[key: string]: any;
} = {};
Expand Down
9 changes: 1 addition & 8 deletions lib/ui/src/components/preview/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,7 @@ const createCanvas = (id: string, baseUrl = 'iframe.html', withLoader = true): A
render: p => {
return (
<Consumer filter={mapper}>
{({
customCanvas,
storyId,
viewMode,
queryParams,
getElements,
isLoading,
}: ReturnType<typeof mapper>) => (
{({ customCanvas, storyId, viewMode, queryParams, getElements, isLoading }) => (
<ZoomConsumer>
{({ value: scale }) => {
const wrappers = [...defaultWrappers, ...getWrapper(getElements)];
Expand Down
8 changes: 4 additions & 4 deletions lib/ui/src/components/preview/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const fullScreenTool: Addon = {
match: p => p.viewMode === 'story',
render: () => (
<Consumer filter={fullScreenMapper}>
{({ toggle, value }: ReturnType<typeof fullScreenMapper>) => (
{({ toggle, value }) => (
<S.DesktopOnly>
<IconButton
key="full"
Expand Down Expand Up @@ -67,7 +67,7 @@ export const copyTool: Addon = {
match: p => p.viewMode === 'story',
render: () => (
<Consumer filter={copyMapper}>
{({ baseUrl, storyId, origin, pathname, queryParams }: ReturnType<typeof copyMapper>) => (
{({ baseUrl, storyId, origin, pathname, queryParams }) => (
<IconButton
key="copy"
onClick={() =>
Expand All @@ -93,7 +93,7 @@ export const ejectTool: Addon = {
match: p => p.viewMode === 'story',
render: () => (
<Consumer filter={ejectMapper}>
{({ baseUrl, storyId, queryParams }: ReturnType<typeof ejectMapper>) => (
{({ baseUrl, storyId, queryParams }) => (
<IconButton
key="opener"
href={`${baseUrl}?id=${storyId}${stringifyQueryParams(queryParams)}`}
Expand Down Expand Up @@ -133,7 +133,7 @@ export const createTabsTool = (tabs: Addon[]): Addon => ({
title: 'title',
render: () => (
<Consumer filter={tabsMapper}>
{({ viewMode, storyId, path, location }: ReturnType<typeof tabsMapper>) => (
{({ viewMode, storyId, path, location }) => (
<Fragment>
<TabBar key="tabs">
{tabs
Expand Down
4 changes: 1 addition & 3 deletions lib/ui/src/containers/notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ export const mapper = ({ state }: Combo) => {
};

const NotificationConnect: FunctionComponent<any> = props => (
<Consumer filter={mapper}>
{(fromState: ReturnType<typeof mapper>) => <Notifications {...props} {...fromState} />}
</Consumer>
<Consumer filter={mapper}>{fromState => <Notifications {...props} {...fromState} />}</Consumer>
);

export default NotificationConnect;
4 changes: 1 addition & 3 deletions lib/ui/src/containers/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ const mapper = ({ state, api }: Combo) => ({
});

const Panel: FunctionComponent<any> = props => (
<Consumer filter={mapper}>
{(customProps: ReturnType<typeof mapper>) => <AddonPanel {...props} {...customProps} />}
</Consumer>
<Consumer filter={mapper}>{customProps => <AddonPanel {...props} {...customProps} />}</Consumer>
);

export default Panel;
2 changes: 1 addition & 1 deletion lib/ui/src/containers/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function getBaseUrl(): string {

const PreviewConnected = React.memo<{ id: string; withLoader: boolean }>(props => (
<Consumer filter={mapper}>
{(fromState: ReturnType<typeof mapper>) => {
{fromState => {
const p = {
...props,
baseUrl: getBaseUrl(),
Expand Down
4 changes: 1 addition & 3 deletions lib/ui/src/containers/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,7 @@ export const mapper = ({ state, api }: Combo) => {
};

const Sidebar: FunctionComponent<any> = props => (
<Consumer filter={mapper}>
{(fromState: ReturnType<typeof mapper>) => <SidebarComponent {...props} {...fromState} />}
</Consumer>
<Consumer filter={mapper}>{fromState => <SidebarComponent {...props} {...fromState} />}</Consumer>
);

export default Sidebar;