From 78414f99547d047906bfb78d617e26db71c652f7 Mon Sep 17 00:00:00 2001 From: leutinatasya Date: Thu, 3 Oct 2024 17:03:27 +0300 Subject: [PATCH 1/2] fix: fix item life cycle callbacks for mobile --- src/components/GridItem/GridItem.js | 37 +++-------------- src/components/Item/Item.js | 46 +++++++++++++++++---- src/components/MobileLayout/MobileLayout.js | 33 +-------------- src/hocs/prepareItem.js | 24 ++++------- 4 files changed, 54 insertions(+), 86 deletions(-) diff --git a/src/components/GridItem/GridItem.js b/src/components/GridItem/GridItem.js index 48fa879..2ae028b 100644 --- a/src/components/GridItem/GridItem.js +++ b/src/components/GridItem/GridItem.js @@ -57,6 +57,9 @@ class GridItem extends React.PureComponent { forwardedPluginRef: PropTypes.any, isPlaceholder: PropTypes.bool, + onItemMountChange: PropTypes.func, + onItemRender: PropTypes.func, + // from react-grid-layout: children: PropTypes.node, className: PropTypes.string, @@ -146,36 +149,6 @@ class GridItem extends React.PureComponent { }); }; - onMountChange = (isMounted) => { - if (isMounted) { - this._inited = true; - - this.props.onItemMountChange?.(this.props.item, { - isAsync: this._isAsyncItem, - isMounted: isMounted, - }); - - if (!this._isAsyncItem) { - this.props.onItemRender?.(this.props.item); - } - } else { - this.props.onItemMountChange?.(this.props.item, { - isAsync: this._isAsyncItem, - isMounted: isMounted, - }); - } - }; - - onBeforeLoad = () => { - this._isAsyncItem = true; - - return this.onLoad; - }; - - onLoad = () => { - this.props.onItemRender?.(this.props.item); - }; - render() { // из-за бага, что Grid Items unmounts при изменении static, isDraggable, isResaizable // https://github.com/STRML/react-grid-layout/issues/721 @@ -244,8 +217,8 @@ class GridItem extends React.PureComponent { adjustWidgetLayout={this.props.adjustWidgetLayout} layout={this.props.layout} forwardedPluginRef={this.props.forwardedPluginRef} - onMountChange={this.onMountChange} - onBeforeLoad={this.onBeforeLoad} + onItemMountChange={this.props.onItemMountChange} + onItemRender={this.props.onItemRender} /> {!noOverlay && this.renderOverlay()} diff --git a/src/components/Item/Item.js b/src/components/Item/Item.js index 4e292b3..a1186d5 100644 --- a/src/components/Item/Item.js +++ b/src/components/Item/Item.js @@ -16,18 +16,47 @@ const Item = ({ type, isPlaceholder, forwardedPluginRef, - onMountChange, + onItemRender, + onItemMountChange, + item, }) => { + const _isAsyncItem = React.useRef(false); + const isRegisteredType = registerManager.check(type); React.useLayoutEffect(() => { if (isRegisteredType && !isPlaceholder) { - onMountChange?.(true); + onItemMountChange?.(item, { + isAsync: _isAsyncItem.current, + isMounted: true, + }); + + if (!_isAsyncItem.current) { + onItemRender?.(item); + } + return () => { - onMountChange?.(false); + onItemMountChange?.(item, { + isAsync: _isAsyncItem.current, + isMounted: false, + }); }; } - }, []); + }, [item]); + + const onLoad = React.useCallback(() => { + onItemRender?.(item); + }, [item, onItemRender]); + + const onBeforeLoad = React.useCallback(() => { + _isAsyncItem.current = true; + + return onLoad; + }, [onLoad]); + + const itemRendererProps = React.useMemo(() => { + return {...rendererProps, onBeforeLoad}; + }, [rendererProps, onBeforeLoad]); if (!isRegisteredType) { console.warn(`type [${type}] не зарегистрирован`); @@ -39,14 +68,14 @@ const Item = ({
{registerManager .getItem(type) - .placeholderRenderer?.(rendererProps, forwardedPluginRef) || null} + .placeholderRenderer?.(itemRendererProps, forwardedPluginRef) || null}
); } return (
- {registerManager.getItem(type).renderer(rendererProps, forwardedPluginRef)} + {registerManager.getItem(type).renderer(itemRendererProps, forwardedPluginRef)}
); }; @@ -57,8 +86,9 @@ Item.propTypes = { registerManager: PropTypes.object, type: PropTypes.string, isPlaceholder: PropTypes.bool, - onMountChange: PropTypes.func, - onBeforeLoad: PropTypes.func, + onItemRender: PropTypes.func, + onItemMountChange: PropTypes.func, + item: PropTypes.object, }; export default prepareItem(Item); diff --git a/src/components/MobileLayout/MobileLayout.js b/src/components/MobileLayout/MobileLayout.js index cef66f2..29c29a8 100644 --- a/src/components/MobileLayout/MobileLayout.js +++ b/src/components/MobileLayout/MobileLayout.js @@ -85,36 +85,6 @@ export default class MobileLayout extends React.PureComponent { return this._memoAdjustWidgetLayout[index]; }; - onMountChange = (isMounted) => { - if (isMounted) { - this._inited = true; - - this.context.onItemMountChange?.(this.props.item, { - isAsync: this._isAsyncItem, - isMounted: isMounted, - }); - - if (!this._isAsyncItem) { - this.context.onItemRender?.(this.props.item); - } - } else { - this.context.onItemMountChange?.(this.props.item, { - isAsync: this._isAsyncItem, - isMounted: isMounted, - }); - } - }; - - onBeforeLoad = () => { - this._isAsyncItem = true; - - return this.onLoad; - }; - - onLoad = () => { - this.context.onItemRender?.(this.props.item); - }; - render() { const {config, layout} = this.context; @@ -141,7 +111,8 @@ export default class MobileLayout extends React.PureComponent { adjustWidgetLayout={this.getMemoAdjustWidgetLayout(index)} forwardedPluginRef={this.getMemoForwardRefCallback(index)} onMountChange={this.onMountChange} - onBeforeLoad={this.onBeforeLoad} + onItemMountChange={this.context.onItemMountChange} + onItemRender={this.context.onItemRender} /> ); diff --git a/src/hocs/prepareItem.js b/src/hocs/prepareItem.js index cc16705..229f1bd 100644 --- a/src/hocs/prepareItem.js +++ b/src/hocs/prepareItem.js @@ -16,10 +16,11 @@ export function prepareItem(Component) { height: PropTypes.number, transform: PropTypes.string, isPlaceholder: PropTypes.bool, - onBeforeLoad: PropTypes.func, + + onItemRender: PropTypes.func, + onItemMountChange: PropTypes.func, forwardedPluginRef: PropTypes.any, - onMountChange: PropTypes.func, }; shouldComponentUpdate(nextProps) { @@ -44,16 +45,7 @@ export function prepareItem(Component) { _currentRenderProps = {}; getRenderProps = () => { - const { - id, - width, - height, - item, - adjustWidgetLayout, - layout, - isPlaceholder, - onBeforeLoad, - } = this.props; + const {id, width, height, item, adjustWidgetLayout, layout, isPlaceholder} = this.props; const {itemsState, itemsParams, registerManager, settings, context, editMode} = this.context; const {data, defaults, namespace} = item; @@ -64,7 +56,6 @@ export function prepareItem(Component) { params: itemsParams[id], state: itemsState[id], onStateAndParamsChange: this._onStateAndParamsChange, - onBeforeLoad, width, height, id, @@ -90,7 +81,8 @@ export function prepareItem(Component) { }; render() { - const {item, isPlaceholder, forwardedPluginRef, onMountChange} = this.props; + const {item, isPlaceholder, forwardedPluginRef, onItemMountChange, onItemRender} = + this.props; const {registerManager} = this.context; const {type} = item; @@ -101,7 +93,9 @@ export function prepareItem(Component) { registerManager={registerManager} type={type} isPlaceholder={isPlaceholder} - onMountChange={onMountChange} + onItemMountChange={onItemMountChange} + onItemRender={onItemRender} + item={item} /> ); } From 6e7fecc8690cb99462836632aae4ea1c354e8703 Mon Sep 17 00:00:00 2001 From: leutinatasya Date: Fri, 4 Oct 2024 14:00:38 +0300 Subject: [PATCH 2/2] fix: review issues --- src/components/Item/Item.js | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/components/Item/Item.js b/src/components/Item/Item.js index a1186d5..4fa6c7f 100644 --- a/src/components/Item/Item.js +++ b/src/components/Item/Item.js @@ -20,36 +20,44 @@ const Item = ({ onItemMountChange, item, }) => { - const _isAsyncItem = React.useRef(false); + // to avoid too frequent re-creation of functions that do not affect the rendering + const isAsyncItemRef = React.useRef(false); + const itemRef = React.useRef(item); + const onItemRenderRef = React.useRef(onItemRender); + const onItemMountChangeRef = React.useRef(onItemMountChange); + + itemRef.current = item; + onItemRenderRef.current = onItemRender; + onItemMountChangeRef.current = onItemMountChange; const isRegisteredType = registerManager.check(type); React.useLayoutEffect(() => { if (isRegisteredType && !isPlaceholder) { - onItemMountChange?.(item, { - isAsync: _isAsyncItem.current, + onItemMountChangeRef.current?.(itemRef.current, { + isAsync: isAsyncItemRef.current, isMounted: true, }); - if (!_isAsyncItem.current) { - onItemRender?.(item); + if (!isAsyncItemRef.current) { + onItemRenderRef.current?.(itemRef.current); } return () => { - onItemMountChange?.(item, { - isAsync: _isAsyncItem.current, + onItemMountChangeRef.current?.(itemRef.current, { + isAsync: isAsyncItemRef.current, isMounted: false, }); }; } - }, [item]); + }, []); const onLoad = React.useCallback(() => { - onItemRender?.(item); - }, [item, onItemRender]); + onItemRenderRef.current?.(itemRef.current); + }, []); const onBeforeLoad = React.useCallback(() => { - _isAsyncItem.current = true; + isAsyncItemRef.current = true; return onLoad; }, [onLoad]);