使用 React 钩子和备忘录时如何防止子组件重新渲染? [英] How to prevent child component from re-rendering when using React hooks and memo?

查看:54
本文介绍了使用 React 钩子和备忘录时如何防止子组件重新渲染?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始尝试 React 钩子,我想知道如何防止子组件在父组件重新渲染时重新渲染.我正在寻找类似于在 componentDidUpdate 中返回 false 的内容.我的问题似乎源于我在子组件中调用的单击处理程序以更改父组件中的状态.由于该函数是在父组件中创建的,因此它会在每个父渲染上创建新的,这会触发子组件中的 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 }) {函数 handleClick(){更改项目();}返回 (<div>名称:{item.name} 值:{item.value}<button onClick={handleClick}>更改父级中的状态</button>

);});

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

我对反应还很陌生,刚刚开始玩钩子,所以我可能遗漏了一些明显的东西.

解决方案

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

function Parent() {const [item, setItem] = useState({ name: "item", value: 0 });const handleChangeItem = useCallback(() => {setItem(prevItem => ({ ...prevItem, value: prevItem.value + 1 }));}, []);返回 (<>名称:{item.name} 值:{item.value}<Child changeItem={handleChangeItem}/></>);}const Child = React.memo(function Child({ item, changeItem }) {函数 handleClick() {更改项目();}console.log("子渲染");返回 (<div><button onClick={handleClick}>更改父级中的状态</button>

);});

工作演示

PS 感谢@danAbramov 的指导

I just started experimenting with React hooks and I'm wondering how I can prevent a child component from re-rendering when it's parent re-renders. I'm looking for something similar to returning false in componentDidUpdate. My issue seems to stem from the click handler I'm calling in the child component to change state in the parent component. Since the function is created in the parent component, it is created new on each parent render which triggers a prop change in the child component, which then causes the child to re-render (I think). Here is some sample code to help illustrate the situation.

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>
    );
});

How do I prevent Child component from rendering every time Parent component renders? Should handleChangeItem in the parent live someplace else so that it is not re-created on each render? If so, how does it get access to item and setItem returned by useState?

I'm pretty new to react and just started playing with hooks so I'm probably missing something obvious.

解决方案

In your case it doesn't really makes sense to memoize Child because if item changes, the child has to re-render. However if there is a case that props do not change , but still the child is re-rendering due to the functions getting recreated you would make use of useCallback hook to memoize the functions, on each render. Also since you have memoized the handler, you should make use of the callback method to update state since item inside the handler will only refer to the value it had when the function was initially created

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

这篇关于使用 React 钩子和备忘录时如何防止子组件重新渲染?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆