神奇的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
来源:掘金