神奇的children
我们有一个需求,需要通过 Provider 传递一些主题信息给子组件
1 | import React, { useContext, useState } form "react"; |
这段代码看起来没啥问题,也很符合撸起袖子就干的直觉,但是却会让 ChildNonTheme 这个不关心皮肤的子组件,在皮肤状态更改的时候也进行无效的重新渲染。
这本质上是由于React是自上而下递归更新,<ChildNonTheme /> 这样的代码会被 babel 翻译成 React.createElement(ChildNonTheme) 这样的函数调用,React官方经常强调props是immutable 的,所以在每次调用函数式组件的时候,都会生成一份新的 props 引用。
来看下 createElement 的返回结构:
1 | const childNonThemeElement = { |
正是由于这个新的 props 引用,导致 ChildNonTheme 这个组件也重新渲染了
那么如何避免这个无效的重新渲染呢?关键词是巧妙利用 children
1 | import React, { useContext, useState } from "react"; |
没错,唯一的区别就是我把控制状态的组件和负责展示的子组件给抽离开了,通过
children传入后直接渲染,由于children从外部传入的,也就是说ThemeApp这个组件内部不会再有React.createElement这样的代码,那么在setTheme触发重新渲染后,children完全没有改变,所以可以直接复用。
让我们再看一下被ThemeApp包裹下的<ChildNonTheme />,它会作为children传递给ThemeApp,ThemeApp内部的更新完全不会触发外部的React.createElement,所以会直接复用之前的element结果:
1 | // 完全复用,props 也不会改变。 |

在改变皮肤之后,控制台空空如也!优化达成。
总结下来,就是要把渲染比较费时,但是不需要关心状态的子组件提升到「有状态组件」的外部,作为 children 或者props传递进去直接使用,防止被带着一起渲染。
作者:ssh_晨曦时梦见兮
链接:https://juejin.im/post/6889247428797530126
来源:掘金