React性能优化(二):将可变部分与不变部分分离
前言
大家好,我是疯狂的小波。在上一节# 一文看懂React优化原理及方案中,我们介绍了为什么要做性能优化,React的更新渲染机制,以及根据这个机制找到的3个性能优化方案。
这一节,我们就来看看第一种优化方案:将可变部分与不变部分分离
先简单来说下,什么是可变部分
。
在 React
中,只要组件的state数据
有变更,当前组件就会重新渲染。state数据
有3个组成部分:props
、state
、context
,只要这几个数据会产生变更,我们就称使用这部分数据的内容为可变部分。
props
、context
是基于state
的扩展,其实就是父级、祖先级组件传递过来的state
那应该怎么进行分离呢?可以将数据会变动的内容单独拆分到一个组件中,这样就不会影响到父节点和其他的同级节点。
一个简单的例子
如,下面代码中:每次点击p
标签更改 count
值时,App
、Children
组件都会重新渲染一次,即使此时 Children
组件的数据并没有任何变动。如果 App
中还有其他的组件,也会重新渲染,显然这是不符合我们预期的,造成了性能浪费。
function App() { const [count, setCount] = useState(0) const add = () => { setCount(count + 1) } return ( <div className="App"> <p onClick={add}>{count}</p> <Children /> </div> ); } function Children() { console.log("子组件渲染"); return <div>子组件</div> } 复制代码
这时,我们就可以将 可变的这一部分内容(count
),单独拆分到一个组件中,进行隔离。如下:
function App() { return ( <div className="App"> <Count /> <Children /> </div> ); } function Count() { const [count, setCount] = useState(0) const add = () => { setCount(count + 1) } return <p onClick={add}>{count}</p> } 复制代码
我们将 count
数据相关内容单独拆分到了 Count
组件中,此时再点击 p
标签变更 count
时,App
、Children
组件也不会重新渲染了。这样就达到了我们的目的,只更新数据变更的内容。
我们可以看到,进行可变数据分离的目的,就是将变更的那一部分数据拆分到独立的组件中,这样父组件数据就不会变更,父组件完成了性能优化,不会重新渲染,其他子组件 props
没有变更的也就不会重新渲染了。
这也就是为什么我们都非常提倡合理的进行组件拆分的原因。不光是更有利于项目的可维护性、可读性,合理的组件拆分同时也能提高项目的性能。
复杂一点的例子
还是基于上面的demo,如果此时 App
组件中,也有部分内容使用到了 count
,该怎么处理?
function App() { const [count, setCount] = useState(0) const add = () => { setCount(count + 1) } return ( <div className="App" title={count}> <p onClick={add}>{count}</p> <Children /> </div> ); } 复制代码
如上,我们在 App
的根节点上,将 count
作为 title
使用,此时就不能简单的像刚刚那样,把这部分内容拆分成一个完全独立的组件了,因为内部还有 Children
组件。此时,也可以如下处理:
function App() { return ( <CountWrapper> <Children /> </CountWrapper> ); } function CountWrapper({children}) { const [count, setCount] = useState(0) const add = () => { setCount(count + 1) } return ( <div className="App" title={count}> <p onClick={add}>{count}</p> {children} </div> ) } 复制代码
还是将 count
的相关内容拆分到到组件 CountWrapper
中,然后通过组件的 props.children
属性渲染子组件。此时 count
数据变更,也只会重新渲染 CountWrapper
组件,App
、Children
组件不会重新渲染。
这种方式可能并不是那么好理解,并且在结构更复杂时,不一定适用。
无法分离时
有时父组件的数据可能会有很多,并且可能会将props
传递给多个子组件,此时就很难将所有的数据变更都拆分到子组件中了。这种情况下,父组件必然就会产生数据变更,导致重新渲染,其子组件也会全部重新渲染。
这种情况下上面的这种优化策略就无法满足我们了,但是我们可以使用前面提到的第二种优化方案 :使用性能优化API,进行处理。也就是我们下一章节的内容。
作者:疯狂的小波
链接:https://juejin.cn/post/7169773969115971598