From 7b9cd15935462b20ccba23d0f8fcf6abcc73bf45 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 14 Feb 2020 19:51:40 +0100 Subject: [PATCH 1/3] IMPROVE the types & performance of lib/api by making the Consumer component a FunctionComponent that auto-memoizes --- lib/api/package.json | 1 - lib/api/src/index.tsx | 97 ++++++++++++++++++++----------------------- 2 files changed, 46 insertions(+), 52 deletions(-) diff --git a/lib/api/package.json b/lib/api/package.json index 4973b263742..ea1b22ad8a4 100644 --- a/lib/api/package.json +++ b/lib/api/package.json @@ -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", diff --git a/lib/api/src/index.tsx b/lib/api/src/index.tsx index 0ff0f611655..5b94f84c336 100644 --- a/lib/api/src/index.tsx +++ b/lib/api/src/index.tsx @@ -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, @@ -115,16 +122,16 @@ interface Children { type StatePartial = Partial; -export type Props = Children & RouterData & ProviderData & DocsModeData; +export type ManagerProviderProps = Children & RouterData & ProviderData & DocsModeData; -class ManagerProvider extends Component { +class ManagerProvider extends Component { api: API; modules: any[]; static displayName = 'Manager'; - constructor(props: Props) { + constructor(props: ManagerProviderProps) { super(props); const { provider, @@ -211,7 +218,7 @@ class ManagerProvider extends Component { this.api = api; } - static getDerivedStateFromProps = (props: Props, state: State) => { + static getDerivedStateFromProps = (props: ManagerProviderProps, state: State) => { if (state.path !== props.path) { return { ...state, @@ -234,7 +241,7 @@ class ManagerProvider extends Component { }); } - shouldComponentUpdate(nextProps: Props, nextState: State) { + shouldComponentUpdate(nextProps: ManagerProviderProps, nextState: State) { const prevState = this.state; const prevProps = this.props; @@ -254,57 +261,45 @@ class ManagerProvider extends Component { api: this.api, }; - // @ts-ignore - const content: ReactNode = typeof children === 'function' ? children(value) : children; - - return {content}; + return ( + + {children} + + ); } } -interface ConsumerProps { - filter?: (combo: C) => S; - pure?: boolean; - children: (d: S | C) => ReactElement | null; +interface ManagerConsumerProps

{ + filter?: (combo: Combo) => P; + children: ReactNode | FunctionComponent

; } -interface SubState { - [key: string]: any; -} +const defaultFilter = (c: Combo) => c; -class ManagerConsumer extends Component> { - prevChildren?: ReactElement | null; +function ManagerConsumerFunc

({ + // @ts-ignore + filter = defaultFilter, + children, +}: ManagerConsumerProps

): ReactElement { + const c = useContext(ManagerContext); + const renderer = useRef(children); + const filterer = useRef(filter); - prevData?: SubState; + if (typeof renderer.current !== 'function') { + return {renderer.current}; + } - dataMemory?: (combo: Combo) => SubState; + const data = filterer.current(c); - constructor(props: ConsumerProps) { - 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

; - return ( - - {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; - }} - - ); - } + return ; + }, l); } export function useStorybookState(): State { @@ -317,7 +312,7 @@ export function useStorybookApi(): API { } export { - ManagerConsumer as Consumer, + ManagerConsumerFunc as Consumer, ManagerProvider as Provider, StoriesHash, Story, @@ -359,7 +354,7 @@ export function useParameter(parameterKey: string, defaultValue?: S) { } type StateMerger = (input: S) => S; -// chache for taking care of HMR +// cache for taking care of HMR const addonStateCache: { [key: string]: any; } = {}; From 79c9c4306cb8d49dbefd4aa1c9e47a34e9cdfdcc Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 14 Feb 2020 20:17:45 +0100 Subject: [PATCH 2/3] IMPROVE performance & typing of lib/api Consumer --- lib/api/src/index.tsx | 4 ++-- lib/ui/src/components/preview/preview.tsx | 9 +-------- lib/ui/src/components/preview/toolbar.tsx | 8 ++++---- lib/ui/src/containers/notifications.tsx | 4 +--- lib/ui/src/containers/panel.tsx | 4 +--- lib/ui/src/containers/preview.tsx | 2 +- lib/ui/src/containers/sidebar.tsx | 4 +--- 7 files changed, 11 insertions(+), 24 deletions(-) diff --git a/lib/api/src/index.tsx b/lib/api/src/index.tsx index 5b94f84c336..fe5163860c6 100644 --- a/lib/api/src/index.tsx +++ b/lib/api/src/index.tsx @@ -271,12 +271,12 @@ class ManagerProvider extends Component { interface ManagerConsumerProps

{ filter?: (combo: Combo) => P; - children: ReactNode | FunctionComponent

; + children: FunctionComponent

| ReactNode; } const defaultFilter = (c: Combo) => c; -function ManagerConsumerFunc

({ +function ManagerConsumerFunc

({ // @ts-ignore filter = defaultFilter, children, diff --git a/lib/ui/src/components/preview/preview.tsx b/lib/ui/src/components/preview/preview.tsx index 0051f246b31..0251c4a2ef3 100644 --- a/lib/ui/src/components/preview/preview.tsx +++ b/lib/ui/src/components/preview/preview.tsx @@ -63,14 +63,7 @@ const createCanvas = (id: string, baseUrl = 'iframe.html', withLoader = true): A render: p => { return ( - {({ - customCanvas, - storyId, - viewMode, - queryParams, - getElements, - isLoading, - }: ReturnType) => ( + {({ customCanvas, storyId, viewMode, queryParams, getElements, isLoading }) => ( {({ value: scale }) => { const wrappers = [...defaultWrappers, ...getWrapper(getElements)]; diff --git a/lib/ui/src/components/preview/toolbar.tsx b/lib/ui/src/components/preview/toolbar.tsx index 5e113d8d177..d197b20cf28 100644 --- a/lib/ui/src/components/preview/toolbar.tsx +++ b/lib/ui/src/components/preview/toolbar.tsx @@ -39,7 +39,7 @@ export const fullScreenTool: Addon = { match: p => p.viewMode === 'story', render: () => ( - {({ toggle, value }: ReturnType) => ( + {({ toggle, value }) => ( p.viewMode === 'story', render: () => ( - {({ baseUrl, storyId, origin, pathname, queryParams }: ReturnType) => ( + {({ baseUrl, storyId, origin, pathname, queryParams }) => ( @@ -93,7 +93,7 @@ export const ejectTool: Addon = { match: p => p.viewMode === 'story', render: () => ( - {({ baseUrl, storyId, queryParams }: ReturnType) => ( + {({ baseUrl, storyId, queryParams }) => ( ({ title: 'title', render: () => ( - {({ viewMode, storyId, path, location }: ReturnType) => ( + {({ viewMode, storyId, path, location }) => ( {tabs diff --git a/lib/ui/src/containers/notifications.tsx b/lib/ui/src/containers/notifications.tsx index 227c04deb56..b71790ab6ba 100644 --- a/lib/ui/src/containers/notifications.tsx +++ b/lib/ui/src/containers/notifications.tsx @@ -13,9 +13,7 @@ export const mapper = ({ state }: Combo) => { }; const NotificationConnect: FunctionComponent = props => ( - - {(fromState: ReturnType) => } - + {fromState => } ); export default NotificationConnect; diff --git a/lib/ui/src/containers/panel.tsx b/lib/ui/src/containers/panel.tsx index 2ca96d5b332..52acba18fe2 100644 --- a/lib/ui/src/containers/panel.tsx +++ b/lib/ui/src/containers/panel.tsx @@ -18,9 +18,7 @@ const mapper = ({ state, api }: Combo) => ({ }); const Panel: FunctionComponent = props => ( - - {(customProps: ReturnType) => } - + {customProps => } ); export default Panel; diff --git a/lib/ui/src/containers/preview.tsx b/lib/ui/src/containers/preview.tsx index 1aaa532a599..ca10e2a759e 100644 --- a/lib/ui/src/containers/preview.tsx +++ b/lib/ui/src/containers/preview.tsx @@ -50,7 +50,7 @@ function getBaseUrl(): string { const PreviewConnected = React.memo<{ id: string; withLoader: boolean }>(props => ( - {(fromState: ReturnType) => { + {fromState => { const p = { ...props, baseUrl: getBaseUrl(), diff --git a/lib/ui/src/containers/sidebar.tsx b/lib/ui/src/containers/sidebar.tsx index ad3c29764bb..485342ea3af 100755 --- a/lib/ui/src/containers/sidebar.tsx +++ b/lib/ui/src/containers/sidebar.tsx @@ -248,9 +248,7 @@ export const mapper = ({ state, api }: Combo) => { }; const Sidebar: FunctionComponent = props => ( - - {(fromState: ReturnType) => } - + {fromState => } ); export default Sidebar; From 64cb247db3e089d10085da0a64475b02b37bd394 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Fri, 14 Feb 2020 20:29:32 +0100 Subject: [PATCH 3/3] RENAME component --- lib/api/src/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/api/src/index.tsx b/lib/api/src/index.tsx index fe5163860c6..62848ab2fb3 100644 --- a/lib/api/src/index.tsx +++ b/lib/api/src/index.tsx @@ -263,7 +263,7 @@ class ManagerProvider extends Component { return ( - {children} + {children} ); } @@ -276,7 +276,7 @@ interface ManagerConsumerProps

{ const defaultFilter = (c: Combo) => c; -function ManagerConsumerFunc

({ +function ManagerConsumer

({ // @ts-ignore filter = defaultFilter, children, @@ -312,7 +312,7 @@ export function useStorybookApi(): API { } export { - ManagerConsumerFunc as Consumer, + ManagerConsumer as Consumer, ManagerProvider as Provider, StoriesHash, Story,