【问题标题】:How can I prevent unnecessary re-renders on the child components in React with Hooks & Context?如何防止在 React with Hooks & Context 中对子组件进行不必要的重新渲染?
【发布时间】:2021-04-30 02:02:59
【问题描述】:

我正在编写一些代码,而这段代码非常庞大。我们有这么多子组件(近 300 个),每个子组件都通过 React Context 使用和操作父组件状态中的值。

注意:我没有从头开始编写此代码。这也意味着我要展示的设计不是我想出来的。

问题:因为每个组件都使用相同的状态,所以会发生很多不必要的重新渲染。每个小的状态变化都会导致每个组件重新渲染。它使网络应用程序滞后。从字面上看,当您在字段中输入某些内容时会有延迟。

我认为,当状态发生变化时,函数会被重建,这就是为什么每个孩子都会被更新,因为上下文提供的值会在状态发生变化后发生变化。

此外,我尝试使用useReducer 代替useState,但效果不佳。除此之外,我尝试在每个子组件上使用React.memo,但无论我尝试什么,compare 函数都没有被触发。 compare 函数仅在状态为 props 的父组件上触发。在这一点上,我什至不确定是什么问题:D

为了提供更具体的设计细节,下面是我们如何定义回调并将回调传递给子组件。

定义:

const [formItemState, setFormState] = React.useState<FormItemState>({} as FormItemState);

const getAppState = useCallback(() => ({ state: props.state as AppState }), [props.state]);

const getAppAction = useCallback(() => ({ action: props.action as AppAction }), [props.action]);

const getFormItemError = useCallback((key: string) => formItemErrorState[key], [
  formItemErrorState,
]);

const getFormItem = useCallback((key: string) => formItemState[key], [formItemState]);

const updateFormItem = useCallback(
    (name: string, formItemData: FormItemData): void => {
        const previousState = getFormItem(name);
        if (!isEqual(previousState, formItemData)) {
            formItemState[name] = formItemData;
            setFormState((state) => ({
                ...state,
                ...formItemState,
            }));
        }
    },
    [formItemState, setFormState]
);

将它们传递给Context.Provider

return (
    <FormContext.Provider
        value={{
            getAppAction,
            getAppState,
            getFormItem,
            updateFormItem
        }}
    >
        <SomeComponent>
            {props.children} // This children contains more than 250 nested components, and each one of them are using these provided functions to interact with the state.
        </SomeComponent>
    </FormContext.Provider>
);

最后一点:如果需要更多信息,请询问我。谢谢!

【问题讨论】:

    标签: reactjs typescript react-hooks react-context


    【解决方案1】:

    你为什么不把你的状态管理重写为 redux 并只提取每个组件上使用的必要状态。 React.memo 仅从 props 中获取更改

    【讨论】:

    • 是的,这似乎是个好方法。但这是很多代码更改 :) 我试图以最小的更改来解决这个问题。
    • 另外,我认为React.memo() 会在组件每次重新渲染之前调用比较函数。
    • @EmirhanKaplan 是的,没错,但它只能获取道具中的更改,因此您需要创建一个组件并将上下文作为道具传递。我猜你正试图在 上使用它,因为这是你调用 useContext 的组件,但你可以在 的所有子组件上使用 React.memo
    • &lt;SomeComponent&gt; &lt;ChildComponent item={item}&gt;&lt;/ChildComponent&gt; &lt;/SomeComponent&gt; 你可以在那个 ChildComponent 上使用你的 React.memo
    • 你说得对,我需要一个中间件来将上下文作为道具传递。这看起来是一个很好的解决方案,不需要太多的努力。再次感谢您的帮助:)
    猜你喜欢
    • 2020-07-07
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    • 2019-05-29
    • 1970-01-01
    • 1970-01-01
    • 2020-06-17
    • 2019-07-28
    相关资源
    最近更新 更多