这是我参与更文挑战的第4天,活动详情查看:查看挑战
React更新机制
React 渲染流程:
React 更新流程:
React在props或state发生改变时,会调用React的render方法,会创建一颗不同的树。
情况一: 对比不同类型的元素
当节点为不同的元素,React会拆卸原有的树,并建新的树。
- 卸载树时,对应的DOM会被销毁,组件实例将执行componentWillUnmount()钩子;
- 创建新树,对应的DOM会被创建以及插入到DOM中,组件实例将执行componentDidMount()等钩子。
下例: React 会销毁 Counter 组件并且重新装载一个新的组件,而不会对Counter进行复用。
<div>
<Counter />
</div>
<span>
<Counter />
</span>
复制代码
情况二: 对比同一类型的元素
当比对两个相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性。
如果是同类型的组件元素:
- 组件会保持不变,React会更新该组件的props,并且调用 componentWillUpdate() 等钩子;
- 下一步,调用 render() 方法,diff 算法将在之前的结果以及新的结果中进行递归。
// 只需要修改 DOM 元素上的 className 属性
<div className='before' title='yes' />
<div className='after' title='yes' />
// 只需要修改 DOM 元素上的 color 样式,无需修改 fontWeight。
<div style={{color:'red',fontWeight:'blod'}} />
<div style={{color:'green',fontWeight:'blod'}} />
复制代码
情况三:对子节点进行递归
在默认条件下,当递归 DOM 节点的子元素时,React 会同时遍历两个子元素的列表;当产生差异时,生成一个
mutation。
在列表最后插入一条数据:
- 前面两两比较是完全相同的,不会产生mutation;
- 最后一个比较,产生一个mutation,将其插入到新的DOM树后面。
在列表中间插入一条数据:
- 在产生差异出开始,后面每条都不一样,产生多个mutation;
- 对性能产生较大的问题;
- 优化:对每条数据填写keys。
render函数调用
当嵌套多层组件,修改上层的state/props会导致render函数被调用,从而重新渲染。
如果修改state/props对子组件没有影响,子组件依旧会重新渲染,造成性能浪费
shouldComponentUpdate()
通过 shouldComponentUpdate()(简称:SCU),来控制是否需要执行render函数。
PureComponent
如果所有的类,我们都需要手动来实现 shouldComponentUpdate,会增加很多工作量。
react提供了一个类 PureComponent,可以帮我们进行判断是否需要执行render函数
- PureCompnent内部是通过shallowEqual方法来判断的;
- shallowEqual是浅层比较state/props判断shouldComponentUpdate返回true/false
高阶组件memo
对于函数式组件,可以使用memo,来进行判断是否执行render
import React, { Component, Fragment, memo, PureComponent } from "react";
const MemoHeader = memo(function Header() {
console.log("MemoHeader 渲染");
return <div>MemoHeader</div>;
});
function Header() {
console.log("Header 渲染");
return <div>我是Header</div>;
}
class PureFooter extends PureComponent {
render() {
console.log("PureFooter 渲染");
return <div>我是PureFooter</div>;
}
}
class Footer extends Component {
render() {
console.log("Footer 渲染");
return <div>我是Footer</div>;
}
}
class App extends Component {
constructor() {
super();
this.state = {
count: 0,
};
}
render() {
console.log("App 渲染");
return (
<Fragment>
<MemoHeader />
<Header />
<div className="center">
<h2>计数:{this.state.count}</h2>
<button onClick={() => this.increment()}>+1</button>
</div>
<PureFooter />
<Footer />
</Fragment>
);
}
increment() {
this.setState({
count: this.state.count + 1,
});
}
}
export default App;
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END