Open zp1112 opened 6 years ago
花了一天时间,看了很多文章,大体上是理解了react的render机制,以及不可变数据在render机制中起到的作用。
安装一个工具可以检测组件是否发生了不必要的渲染。如果发生了不必要的组件渲染,控制台会精确定位并且打印出那些状态触发了不必要的渲染。然后针对性的进行优化,简直是神器啊。
npm i -D why-did-you-update
在index.js加
if (process.env.NOED_ENV !== 'production') { const { whyDidYouUpdate } = require('why-did-you-update'); whyDidYouUpdate(React); }
class App extends component { constructor(props) { super(props); this.state = { count: 0, user: { name: 'zp' } } } handleClick = () => { this.setState({ count: 0 }); } render() { return ( <div> <div onClick={this.handleClick}>点击我</div> <div>{this.state.count}</div> </div> ); } }
保存文件,打开页面,点击点击我,会发现控制台打印出了一个console,提示这个render是不必要的render,count并没有改变,但是组件却重新渲染了。
PureComponent是react自带的继承了component的类,但是在组件re-render的时候加了一层判断,浅比较新的状态和旧的状态是否一致,如果新旧状态的引用不一致,则比较第一层状态值是否改变,上面的例子中count为第一层,值没有改变,所以不重新渲染。
class App extends PureComponent { // ...代码 }
为什么说是浅比较,那是因为假设我现在改更新的是user里面的name属性,name我们看看即便加了purecomponent,是否还会发生不必要的渲染呢。
修改handleClick
handleClick = () => { this.setState({ user: { name: 'zp' } }); }
此时页面console,依然打印出不必要渲染,告知这里的不必要渲染造成的原因是user的引用改变了。
由于purecomponent只比较第一层,所以第二层的user下面的值{name: 'zp'}是个引用。引用改变了,值就不一样了,就会触发re-render。相当于
deepEquals = (obj1, obj2) => { if (obj1 === obj2) { return true; } for (const key of Object.keys(obj2)) { if (obj1.hasOwnProperty(key) && obj1[key] === obj2[key]) { return true; } } return false; } shouldComponentUpdate = (nextProps, nextState) => { return !this.deepEquals(this.state, nextState) || !this.deepEquals(this.props, nextProps); }
手写shouldComponentUpdate和加purecomponent的效果是一样的,只能浅比较。
所以purecomponent解决了浅层次的dom渲染优化,但是对于结构更加复杂的嵌套的数据结构,还是会发生不必要的渲染。
网上很火的数据结构immutable.js,似乎很好的解决了这个问题,让我们看看如何简单的使用immutable.js改造上面的例子
首先本地安装immutable.js。
npm i --save immutable
这里我们先把state改造一下,使用immutable的API改造handleClick,最后render里面的dom渲染再使用API改造一下
this.state = { data: Immutable.fromJS({ count: 0, user: { name: 'zp' } }) } handleClick = () => { this.setState((d) => { return { data: d.data.updateIn(['user', 'name'], () => 'zp') // 这里改变了user里面的name,深层改变 } }) } render() { const data = this.state.data; return ( <div> <div onClick={this.handleClick}>点击我</div> <div>{data.get('count')}</div> <div>{data.getIn(['user', 'name'])}</div> </div> ); }
保存刷新页面,点击,会发现并没有多余的render。cool!
我觉得这样看来,immutable.js真的很强大很诱人,看到没有浪费的render,这让有强迫症的开发人员感到很舒服,但是网上看到immutable.js的弊端也有些,
如果不用ImmutableJS ,那么就要尽量避免使用复杂的结构,最好扁平化数据结构,但是。。。。那是不可能的!!所以,你们看着办吧。
我只想说,虽然我现在的项目并没有使用react,甚至我也没用过ImmutableJS ,但是我对react的爱是不变的,我会保持学习,一直进步。。。。嘿,小哥,招前端吗?
React渲染
花了一天时间,看了很多文章,大体上是理解了react的render机制,以及不可变数据在render机制中起到的作用。
工具
安装一个工具可以检测组件是否发生了不必要的渲染。如果发生了不必要的组件渲染,控制台会精确定位并且打印出那些状态触发了不必要的渲染。然后针对性的进行优化,简直是神器啊。
在index.js加
正常渲染
保存文件,打开页面,点击点击我,会发现控制台打印出了一个console,提示这个render是不必要的render,count并没有改变,但是组件却重新渲染了。
使用PureComponent
PureComponent是react自带的继承了component的类,但是在组件re-render的时候加了一层判断,浅比较新的状态和旧的状态是否一致,如果新旧状态的引用不一致,则比较第一层状态值是否改变,上面的例子中count为第一层,值没有改变,所以不重新渲染。
为什么说是浅比较,那是因为假设我现在改更新的是user里面的name属性,name我们看看即便加了purecomponent,是否还会发生不必要的渲染呢。
修改handleClick
此时页面console,依然打印出不必要渲染,告知这里的不必要渲染造成的原因是user的引用改变了。
由于purecomponent只比较第一层,所以第二层的user下面的值{name: 'zp'}是个引用。引用改变了,值就不一样了,就会触发re-render。相当于
手写shouldComponentUpdate和加purecomponent的效果是一样的,只能浅比较。
所以purecomponent解决了浅层次的dom渲染优化,但是对于结构更加复杂的嵌套的数据结构,还是会发生不必要的渲染。
immutable.js
网上很火的数据结构immutable.js,似乎很好的解决了这个问题,让我们看看如何简单的使用immutable.js改造上面的例子
首先本地安装immutable.js。
这里我们先把state改造一下,使用immutable的API改造handleClick,最后render里面的dom渲染再使用API改造一下
保存刷新页面,点击,会发现并没有多余的render。cool!
用不用
我觉得这样看来,immutable.js真的很强大很诱人,看到没有浪费的render,这让有强迫症的开发人员感到很舒服,但是网上看到immutable.js的弊端也有些,
如果不用ImmutableJS ,那么就要尽量避免使用复杂的结构,最好扁平化数据结构,但是。。。。那是不可能的!!所以,你们看着办吧。
我只想说,虽然我现在的项目并没有使用react,甚至我也没用过ImmutableJS ,但是我对react的爱是不变的,我会保持学习,一直进步。。。。嘿,小哥,招前端吗?