【问题标题】:how to use React.memo with a Component contains children如何使用带有子组件的 React.memo
【发布时间】:2020-06-25 09:56:41
【问题描述】:

需要帮助~

我有两个组件,我用 React.memo 包裹了 Parent:

孩子

const Child = ()=> <div>I'm Child</div

export default Child

父母

const Parent = (props)=> <div>{props.children}</div>

export default React.memo(Parent)

在应用中使用:

const App = () => {
  const [count, setCount] = useState(0)

  return(
    <div>
      <button onClick={()=>setCount(count+1)}></button>

      <Parent>
        <Child></Child>
      </Parent>
    </div>
  )
}

点击按钮,结果:

父组件将重新渲染,所以备忘录不起作用,因为它的子组件是一个函数组件

那么,如何防止重新渲染?

我知道useMemo的解决方法,但是又丑又不友好,你有更好的想法吗?

const App = () => {
  const [count, setCount] = useState(0)

  const children = useMemo(()=><Child></Child>,[])

  return(
    <div>
      <button onClick={()=>setCount(count+1)}></button>

      <Parent>
        {children}
      </Parent>
    </div>
  )
}

【问题讨论】:

  • Child 组件由App 组件渲染。因此,要么将Child 的渲染移动到Parent 组件中,要么将Child 包装在React.memo() 中。
  • 不,不行,我试过了……
  • 好的,所以你的Parent 仍然会重新渲染,因为当App 重新渲染时,它的children 属性在技术上会发生变化,这就是为什么即使React.memo() 也无济于事的原因。基本上最好的解决方法似乎是你使用useMemo 所做的。您必须记住作为孩子传递给 Parent 的内容,否则它将重新渲染。
  • 谢谢,还有另一种方式 React.memo(Parent, ()=>true)。但这不安全……

标签: reactjs react-hooks react-memo


【解决方案1】:
const Memo = React.memo(({ children, value }) => {
  return children
}, (prev, next) => prev.value === next.value)

然后使用它

function Title() {
  const [count, setCount] = useState(0)
  const onClick = () => {
    setCount(c => c + 1)
  }

  const a = ''

  return (
    <>
      <div onClick={onClick}>{count}</div>
      <Memo value={a}>
        <Child>
          <Nothing2 a={a} />
        </Child>
      </Memo>
    </>
  )
}

a 发生变化时,Child 渲染,否则它会退出之前的渲染。

我在我的博客https://javascript.plainenglish.io/can-usememo-skip-a-child-render-94e61f5ad981中概述了它背后的原因

【讨论】:

    【解决方案2】:

    &lt;Parent&gt;&lt;Child/&gt;&lt;/Parent&gt; 移动到一个单独的组件中,并记住那个组件:

    const Family = memo(() => <Parent><Child/></Parent>);
    
    const App = () => {
      const [count, setCount] = useState(0);
    
      return (
        <>
          <button onClick={() => setCount(count => count + 1)}>{count}</button>
          <Family />
        </>
      )
    }
    

    demo

    【讨论】:

      【解决方案3】:
      const children = useMemo(()=><Child></Child>,[])
      

      是最简单的方法。使用memo(Child) 将不起作用,因为jsx 实际上会在您调用&lt;Child /&gt; 时返回一个新对象。 React.memo 默认情况下只使用简单的浅比较,所以真的没有其他直接的方法来解决它。您可以创建自己的最终支持孩子的函数并将其传递给React.memo(MyComp, myChildrenAwareEqual)

      【讨论】:

        【解决方案4】:

        React.memo 包裹你的&lt;Child /&gt;

        const Child = ()=> {
          console.log('render') // fires only once - on initial render
          return <div>I'm Child</div>
        }
        
        const MChild = React.memo(Child);
        const Parent = (props)=> <div>{props.children}</div>
        const MParent = React.memo(Parent)
        
        const App = () => {
          const [count, setCount] = useState(0);
        
          return(
            <div>
              <button onClick={()=>setCount(count+1)}>increment {count}</button>
              <MParent>
                <MChild></MChild>
              </MParent>
            </div>
          )
        }
        
        render(<App />, document.getElementById('root'));
        

        【讨论】:

        • 但是如果您在 Parent 中登录会发生什么?
        • 出于某种原因,我认为这行不通。 MParentchildren 仍然在变化。我认为 useMemo 缓存整个 &lt;Child /&gt; 可以工作,就像在马克西姆的回答中一样。
        猜你喜欢
        • 2021-02-26
        • 2023-01-28
        • 2019-10-12
        • 2021-07-04
        • 2021-05-23
        • 1970-01-01
        • 1970-01-01
        • 2021-10-21
        • 1970-01-01
        相关资源
        最近更新 更多