为什么 React.memo 不能与 `props.children` 属性一起使用?

Ale*_*ase 5 state reactjs react-hooks

我试图将子组件(“Box”)包装起来,React.memo()以避免当父组件因状态更改而重新渲染时不必要地重新渲染它。但这不适用于props.children财产。当我再次尝试而不使用 时props.children,它确实有效!但为什么?props.children如果不使用组合和属性,我该如何实现这一目标memo

(1) 传递组件示例(有效):<Box title="i am a box" />

(2) 传递组件示例(不起作用):<Box> <h1>I am a box</h1> </Box>

///

工作示例(1):

导出默认备忘录 (function Box(props) { return ( <div className='box'><h1>{props.title}</h1></div> ) } );

具有继承性的 Box 组件

父组件: 在此输入图像描述

不工作示例(2):

导出默认备忘录 (function Box(props) { return ( <div className='box'>{props.children}</div> ) } );

具有组合的盒子组件

父组件: 在此输入图像描述

Iva*_*pov 6

我可以解释一下。

\n
    \n
  1. 备忘录进行了轻度比较,没有进行深度比较。
  2. \n
  3. 当您在孩子中传递字符串时,备忘录将与孩子一起工作。
  4. \n
  5. 如果传递一些元素或组件,props.childrens 将包含数组,其中包含传递元素的引用。每个渲染都会收到一个新的数组。一个数组可能有相同的内容,但对数组的引用会不同。这些是不同的数组,备忘录不进行深入比较。它不比较数组、对象的内容,而只比较对它们的引用。
  6. \n
\n

基于上述内容,为什么这不适用于您的示例。您将“h1”元素作为子元素传递。您的子组件中有一个包含一个“h1”元素的数组。对于父级的每次渲染,都会出现一个新数组。是的,它将是一个具有相同内容的数组,但它不是同一个数组,也不是同一个引用。备忘录不进行深度检查。

\n

下面两个示例,包含字符串和元素。

\n
// if you pass string as children, memo will be work\n\nconst MemoizedChildComponent = memo(({children}) => {\n  console.log('render', children) // only one time render, children: "string"\n  return <div>children</div>\n})\n\nconst App = () => {\n  const [count, setCount] = useState(1)\n\n  const handleCountIncrement = () => {\n    setCount(count + 1)\n  }\n\n  return <div>\n    <button onClick={handleCountIncrement}>increase</button>\n    <MemoizedChildComponent>string</MemoizedChildComponent> // pass simple string\n  </div>\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但是,如果您不想\xe2\x80\x99 不想放弃这些元素并想记住它们怎么办?

\n

我建议使用 useMemo 钩子来记忆传递的孩子。

\n

我不会说那很好。但如果您的目标是记住孩子,这将会有所帮助。你无法通过备忘录解决这个问题。没有深度比较,所以备忘和孩子有问题。不要忘记在 useMemo 中指定依赖项,示例中没有,因此依赖项数组为空。

\n
const MemoizedChildComponent = memo(({children}) => {\n  console.log('render', children) // only one time render, because it children memoized in parent component inside useMemo hook. children: [object, object, object]\n  return <div>children</div>\n})\n\nconst App = () => {\n  const [count, setCount] = useState(1)\n\n  const handleCountIncrement = () => {\n    setCount(count + 1)\n  }\n\n  const memoizedChildren = useMemo(() => [\n    <p key="1">asd</p>,\n    <p key="2">asd</p>,\n    <p key="3">asd</p>\n  ], [])\n\n  return <div>\n    <button onClick={handleCountIncrement}>increase</button>\n    <MemoizedChildComponent>{memoizedChildren}</MemoizedChildComponent>\n  </div>\n}\n
Run Code Online (Sandbox Code Playgroud)\n


小智 2

组件的子组件实际上来自其父组件。当父级重新渲染时,它会重新计算所有内容并触发 return 语句。该返回语句中的所有内容都会被重新创建,并且所有子级都被要求重新渲染。

其中一些可能是记忆组件,这将决定它们是否应该根据道具重新渲染。但是,当您将子组件传递给该组件时,对于父组件的每次重新渲染,您都会将子组件的新实例发送到该记忆组件。因此,它会导致它重新渲染。