React 之 props.children 来渲染子组件 ,避免重复渲染

2,483 阅读2分钟

我以前没怎么在意,props.children 和直接组件.jsx 来渲染页面的差异性

下面例子不会重复渲染 !

  • 当点击 Click组件 按钮时,count增加,<Clicker />组件重新渲染,同时子组件Render并不会重新渲染
  • 我们还是借用了children 的机制,直接渲染,那么在父组件当中就没有 Ract.createElement(Son)  这个api的执行,因此就不会造成重复的渲染!
  • 里面的原理有 diff算法fiber节点
function App() {
  return (
    <div className="app">
      <Click>
        <Render />
      </Click>
    </div>
  );
}

function Click({ children }) {
  const [count, setCount] = useState(0);
  return (
    <div className="click">
      <h2>{count}</h2>
      <button onClick={() => setCount(count + 1)}>+++</button>
      {children}
    </div>
  );
}

function Render() {
  const count = React.useRef(0);
  React.useEffect(() => {
    console.log("component rendered", count.current++);
  });
  return <div className="render"><p>sub</p></div>;
}
  • 他的前后props永远是相等的,一个节点更新前后props相等,且该节点没有更新,并且其子树中也没有更新,这种情况下以该节点为根的fiber子树的reconciliation过程就会到此为止停止 diff
  • <Render />不是<Click>的子组件,它是App的子组件,对于<Click>来说,<Render />是他的一个属性props.children。所以<Render />是否re-render取决于App,而App没有更新
  • Render函数中是以props.children的形式体现出来的,而App渲染时,其props并未变化,相应的props.children,同样没有变化,所以不会重新渲染。

下面例子会重复渲染 !

function App() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <h2>{count}</h2>
      <button onClick={() => setCount(count + 1)}>+++</button>
      <Render />
    </div>
  );
}

function Render() {
  const count = React.useRef(0);
  useEffect(() => {
    console.log("component rendered", count.current++);
  });

  return ( <div className="Render"><p>sub</p></div> )
}
  • Render> 终会编译成 React.createElement(Render, null) 这个形式,注定要重复渲染这个子组件, 返回结果是一个ReactElement全新的引用,而它里面的props也是一个全新的对象
  • 由于RenderJSX元素App中被重新创建,所以他的props就不相等了
  • 如果不想让他重复渲染,可以将<Render> 这个组件包裹在memo中这时候比较他更新前后的props是否变更,就会转换为对其中的每个属性进行浅比较
  • 状态维护在App中,<Render />是App的子组件,所以会刷新

参考: juejin.cn/post/702317…

结语

前端react QQ群:788023830 ---- React/Redux - 地下老英雄

前端交流QQ群:249620372 ---- FRONT-END-JS前端

(我们的宗旨是,为了加班,为了秃顶……,仰望大佬),希望小伙伴们加群一起学习