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

时间:2019-01-03 00:58:23

标签: reactjs react-hooks

我刚刚开始使用React钩子进行实验,我想知道如何在父组件重新渲染子组件时阻止子组件重新渲染。我正在寻找类似于在componentDidUpdate中返回false的东西。我的问题似乎源于我在子组件中调用以更改父组件状态的单击处理程序。由于该功能是在父级组件中创建的,因此会在每个父级渲染上创建新功能,从而触发子级组件中的属性更改,然后导致子级重新渲染(我认为)。这是一些示例代码来帮助说明这种情况。

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是否应该居住在其他地方,以便不在每个渲染器上重新创建?如果是这样,它如何访问item返回的setItemuseState

我是个很新的反应者,刚开始玩钩子,所以我可能缺少明显的东西。

2 个答案:

答案 0 :(得分:6)

在您的情况下,记住Child确实没有任何意义,因为如果项目发生更改,则必须重新渲染Child。但是,如果情况是道具没有变化,但是由于重新创建了函数,仍然在重新渲染孩子,则您将在每个渲染器上使用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>
  );
});

Working demo

P.S。Credit to @danAbramov for the direction

答案 1 :(得分:0)

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

所有这些的关键在于,派发永不改变,这与在每个渲染器中创建的回调不同。