【问题标题】:Prevent re-rendering in ReactJS of all childs on onChange event防止在 onChange 事件中所有子项在 ReactJS 中重新渲染
【发布时间】:2020-04-29 21:33:20
【问题描述】:

我正在设置一个简单的仪表板来用 ReactJS 挑战我自己,但是我有一些问题阻止了无用的重新渲染。

我有一个名为 App 的根组件,用于获取一些数据。

const App = () => {
    const [data, setData] = useState(null);
    const [list1, setList1] = useState(null);
    const [list2, setList2] = useState(null);
    const [list3, setList3] = useState(null);
    const [list4, setList4] = useState(null);

    useEffect(() => {
        const fetchData = fetchDataInSomeWay();

        const fetchedData = getData(fetchData);
        const list1Data = getList1(fetchData);
        setList1(list1Data);
        setData(fetchedData);
    });

   ...

    { data !== null
        && (
            <Parent
                data={data}
                list1={list1}
                list2={list2}
                list3={list3}
                list4={list4}
            />
};

然后我设置了一个父组件,我在其中创建了一些 Select 组件和其他依赖于 select 选择的值的元素。 对于使用 useState() 创建的每个列表状态,我都有一个 Select 元素;

const Google = ({
    data,
    list1,
    list2,
    list3,
    list4,
}) => {
    const [typeValue, setTypeValue] = useState('someValue');
    const [list1Value, setList1Value] = useState(list1[0]);
    const [list2Value, setList2Value] = useState(list2[0]);
    const [list3Value, setList3Value] = useState(list3[0]);
    const [list4Value, setList4Value] = useState(list4[0]);

    const onChangeSelectTypeValue = (value) => {
        setTypeValue(value);
    };

    ...

    const selectTypeValueElement = (
        <SelectElement
            select={selectType}
            value={[typeValue]}
            onChangeValue={onChangeSelectTypeValue}
            values={list1Value}
        />
    );

    ...

    <div className="interactionHeaderChart">
        { selectTypeValueElement }
        ...
    </div>
};

然后我有一个 Select 元素,我不存储状态,但将选择的选项传递给 Parent 组件。

const SelectElement = ({
    select, value, values, onChangeValue,
}) => {
    ...
    <Select
        ...
        value={value[0]}
        onChange={onChangeValue}
    >
    ...
};

现在,当我从一个 Select 中选择某个选项时,Parent 的状态发生变化并且所有 Childs 重新渲染,所有 Selects 组件以及其他依赖于 select 选择的值的组件。

我可以阻止所有 Select 组件重新渲染吗?我可以避免重新渲染不依赖于所选选项值的所有其他组件吗? 状态已经从 onChange 函数而不是从 useEffect() 改变的事实让我感到困惑,我无法理解如何解决它。

谢谢。

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    你应该看看 shouldComponentUpdate:

    https://reactjs.org/docs/react-component.html#shouldcomponentupdate

    通常,为了将它与您的 SelectElement 组件一起使用,您首先必须将其转换为一个类。然后,您可以向其添加 shouldComponentUpdate 函数并检查上一个和下一个道具是否相同。如果它们相同,请不要更新。

    但是,如果您的道具不是复杂的对象,您实际上可以将您的 SelectElement 重新创建为 PureComponent。这将自动检查道具,如果它们相同则不会重新渲染。

    例如

    class SelectElement extends React.PureComponet {...
    

    【讨论】:

    • React.memo (reactjs.org/docs/react-api.html#reactmemo) 为函数组件。
    • @Morris 感谢您的回答,但是有没有使用类的解决方案?因为挑战之一是使用 Hooks 而不是 Class。特别是我现在正在做的是将Class翻译成Hooks。 SelectElement 以前是 PureComponent。
    • @JakubJanczyk 我忘了提。我已经尝试将 React.memo 与 const SelectElement = React.memo(({..}) =&gt; {...});, 之类的东西一起使用,但同时所有 SelectElement 都被突出显示。
    • @lezan 那是因为React.memo 仅通过检查属性引用是否不同来工作。在您的情况下,道具 value={[typeValue]}onChangeValue={onChangeSelectTypeValue} 在每次重新渲染时都会有所不同。在第一种情况下,因为它每次都是新数组,在第二种情况下,因为函数被重新创建。相应地使用useMemouseCallback 并包装你的变量/函数以避免这个问题。让我知道是否清楚 - 如果需要,我会详细说明更长的答案。
    • @JakubJanczyk 感谢您花时间回复。我会尽快检查并报告结果。
    【解决方案2】:

    您可以使用备忘录来避免重新渲染。

    方式一:

    const NestedComponent = () => {
        return (
            <div>
                ContainerComponent
            </div>
        );
    };
    export default React.memo(NestedComponent);
    

    方式 2:

    function ParentComponent(a, b) {
      const childComponent = React.useMemo(() => <ChildComponent posts={a} />, [a]);
    
      return (
        <>
          {childComponent}
        </>
      )
    }
    

    【讨论】:

    • 感谢您的回答。让我检查你给我的所有建议,我会报告你的结果。
    • 方式 1 不起作用,正如 here 已经报告的那样,原因是值不是原始值,而是数组和函数。方式 2 不起作用,仍然所有组件都高亮显示。
    猜你喜欢
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    • 2018-03-03
    • 2020-06-17
    • 2018-07-20
    • 2020-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多