使用 React 钩子和备忘录时如何防止子组件重新渲染?

IT技术 reactjs react-hooks
2021-05-24 11:33:34

我刚开始尝试 React 钩子,我想知道如何防止子组件在父组件重新渲染时重新渲染。我正在寻找类似于在componentDidUpdate. 我的问题似乎源于我在子组件中调用的单击处理程序以更改父组件中的状态。由于该函数是在父组件中创建的,因此它在每个父渲染上创建新的,这会触发子组件中的 prop 更改,然后导致子组件重新渲染(我认为)下面是一些示例代码来帮助说明这种情况。

function Parent() {
    const [item, setItem] = useState({ name: "item", value: 0 });

    const handleChangeItem = () => {
        const newValue = item.value + 1;
        setItem({ ...item, value: newValue });
    };

    return <Child item={item} changeItem={handleChangeItem} />;
}

const Child = React.memo(function Child({ item, changeItem }) {
    function handleClick(){
        changeItem();
    }
    return (
        <div>
            Name: {item.name} Value: {item.value}
            <button onClick={handleClick}>change state in parent</button>
        </div>
    );
});

每次父组件渲染时如何防止子组件渲染?handleChangeItem父级是否应该住在其他地方,以便不会在每次渲染时重新创建?如果是这样,它如何访问itemsetItem返回useState

我对react还很陌生,刚刚开始玩钩子,所以我可能错过了一些明显的东西。

2个回答

在您的情况下,记住 Child 并没有真正意义,因为如果项目发生变化,则孩子必须重新渲染。但是,如果在某些情况下 props 没有改变,但由于函数被重新创建,孩子仍然在重新渲染,您将useCallback在每次渲染时使用钩子来记忆函数。此外,由于您已经记住了处理程序,您应该使用回调方法来更新状态,因为item处理程序内部只会引用它在最初创建函数时的值

function Parent() {
  const [item, setItem] = useState({ name: "item", value: 0 });

  const handleChangeItem = useCallback(() => {
    setItem(prevItem => ({ ...prevItem, value: prevItem.value + 1 }));
  }, []);

  return (
    <>
      Name: {item.name} Value: {item.value}
      <Child changeItem={handleChangeItem} />
    </>
  );
}

const Child = React.memo(function Child({ item, changeItem }) {
  function handleClick() {
    changeItem();
  }
  console.log("child render");
  return (
    <div>
      <button onClick={handleClick}>change state in parent</button>
    </div>
  );
});

工作演示

PS 感谢@danAbramov 的指导

Shubham Khatri 准确地回答了原始问题,但我添加此答案是为了指出避免此回调问题的推荐方法。

从文档:

当您具有涉及多个子值的复杂状态逻辑时,useReducer 通常比 useState 更可取。它还可以让您优化触发深度更新的组件的性能,因为您可以向下传递调度而不是回调。

https://reactjs.org/docs/hooks-reference.html#usereducer

从常见问题:

在大型组件树中,我们推荐的另一种方法是通过上下文从 useReducer 传递一个调度函数......

https://reactjs.org/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down

所有这一切的关键是 dispatch 永远不会改变,不像每次渲染都会创建的回调。