- Scheduler(调度器)—— 调度任务的优先级,高优任务优先进入Reconciler
- Reconciler(协调器)—— 负责找出变化的组件
- Renderer(渲染器)—— 负责将变化的组件渲染到页面上
<React16
挂载阶段
单一组件挂载
constructor
componentWillMount
render
componentDidMount
更新阶段
state更新
* 1. shouldComponentUpdate
//返回Boolean 类型的值,判断是否需要更新渲染组件,优化 react 应用的主要手段之一
// 当返回 false 就不会再向下执行生命周期了
// 在这个阶段不可以 setState(),会导致循环调用。
* 2. componentWillUpdate
//这个生命周期主要提供一个时机能够处理一些在 Dom 发生更新之前的事情,
//如获得 Dom 更新前某些元素的坐标、大小等,在这个阶段不可以 setState(),会导致循环调用。
************截止至此, this.props 和 this.state 都还未发生更新******
* 3. render
* 4. componentDidUpdate
//在此时已经完成渲染,Dom 已经发生变化,State 已经发生更新,
//prevProps、prevState 均为上一个状态的值。
props更新
* 1. componentWillReceiveProps(nextProps,nextState)
//生命周期主要为我们提供对 props 发生改变的监听,
//如果你需要在 props 发生改变后,相应改变组件的一些 state。
// 在这个方法中改变 state 不会二次渲染,而是直接合并 state。
* 2. shouldComponentUpdate(nextProps, nextState)
//返回Boolean 类型的值,判断是否需要更新渲染组件,优化 react 应用的主要手段之一
// 当返回 false 就不会再向下执行生命周期了
// 在这个阶段不可以 setState(),会导致循环调用。
* 3. componentWillUpdate
//这个生命周期主要提供一个时机能够处理一些在 Dom 发生更新之前的事情,
//如获得 Dom 更新前某些元素的坐标、大小等,在这个阶段不可以 setState(),会导致循环调用。
************截止至此, this.props 和 this.state 都还未发生更新******
* 4. render
* 5. componentDidUpdate(prevProps, prevState)
//在此时已经完成渲染,Dom 已经发生变化,State 已经发生更新,
//prevProps、prevState 均为上一个状态的值。
卸载阶段
* componentWillUnmount
//此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount 中创建的订阅等。
//componentWillUnmount 中不应调用 setState,因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
import React from 'react';
import './style.css';
class Son extends React.Component {
constructor(props) {
super(props);
console.log('子组件子组件constructor ======>');
this.state = {
number: 1
};
}
// static getDerivedStateFromProps(props, state) {
// console.log('getDerivedStateFromProps =======>');
// return props;
// }
componentWillMount() {
console.log('子组件componentWillMount =====>');
}
componentWillReceiveProps(nextProps, nextState) {
//主要提供对 props 发生改变的监听,如果需要在 props 发生改变后,相应改变组件的一些 state。
//在这个方法中改变 state 不会二次渲染,而是直接合并 state。
console.log(
'子组件componentWillReceiveProps ===>',
'nextProps',
nextProps,
'nextState',
nextState
);
}
componentDidMount() {
console.log('子组件componentDidMount ======>');
}
shouldComponentUpdate(nextProps, nextState) {
//返回Boolean 类型的值,判断是否需要更新渲染组件,优化 react 应用的主要手段之一
// 当返回 false 就不会再向下执行生命周期了
// 在这个阶段不可以 setState(),会导致循环调用。
console.log(
'子组件shouldComponentUpdate ====>',
'nextProps',
nextProps,
'nextState',
nextState,
'this.state',
this.state
);
return true;
}
componentWillUpdate() {
console.log('子组件componentWillUpdate =====>', 'this.state', this.state);
}
componentDidUpdate(prevProps, prevState) {
console.log(
'子组件componentDidUpdate =====>',
'prevProps',
prevProps,
'prevState',
prevState,
'this.state',
this.state
);
}
componentWillUnmount() {
console.log('子组件componentWillUnmount=====>');
}
render() {
console.log('子组件render ========>');
return (
<>
<h1>父组件props{this.props.count}</h1>
<button onClick={() => this.setState({ count: this.state.number + 1 })}>
点击子组件更新状态{this.state.number}
</button>
</>
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
console.log('constructor ======>');
this.state = {
count: 1
};
}
// static getDerivedStateFromProps(props, state) {
// console.log('getDerivedStateFromProps =======>');
// return props;
// }
componentWillMount() {
console.log('componentWillMount =====>');
}
componentWillReceiveProps(nextProps, nextState) {
//主要提供对 props 发生改变的监听,如果需要在 props 发生改变后,相应改变组件的一些 state。
//在这个方法中改变 state 不会二次渲染,而是直接合并 state。
console.log('componentWillReceiveProps ===>', nextProps, nextState);
}
componentDidMount() {
console.log('componentDidMount ======>');
}
shouldComponentUpdate(nextProps, nextState) {
//返回Boolean 类型的值,判断是否需要更新渲染组件,优化 react 应用的主要手段之一
// 当返回 false 就不会再向下执行生命周期了
// 在这个阶段不可以 setState(),会导致循环调用。
console.log(
'shouldComponentUpdate ====>',
// 'nextProps',
// nextProps,
// 'nextState',
// nextState,
'this.state',
this.state
);
return true;
}
componentWillUpdate() {
console.log('componentWillUpdate =====>', 'this.state', this.state.count);
}
componentDidUpdate(prevProps, prevState) {
console.log(
'componentDidUpdate =====>',
'prevProps',
prevProps,
'prevState',
prevState,
'this.state',
this.state
);
}
componentWillUnmount() {
console.log('componentWillUnmount=====>');
}
render() {
console.log('render ========>', this.state.count);
return (
<>
<h1>生命周期测试</h1>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
点击更新状态{this.state.count}
</button>
<Son count={this.state.count} />
</>
);
}
}
export default function App() {
return (
<div>
<h1>Hello StackBlitz!</h1>
<p>Start editing to see some magic happen :)</p>
<Parent />
</div>
);
}
React16+
https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
组件在挂载dom上的时候,会经历 render和commit阶段
Stack Reconciler重构为Fiber Reconciler后,render阶段的任务可能中断/重新开始,对应的组件在render阶段的生命周期钩子(即componentWillXXX)可能触发多次。这种行为和Reactv15不一致,所以标记为UNSAFE。更详细的解释参照这里(opens new window)为此,React提供了替代的生命周期钩子getSnapshotBeforeUpdate。`
Stack Reconciler重构为Fiber Reconciler后,render阶段的任务可能中断/重新开始,对应的组件在render阶段的生命周期钩子(即componentWillXXX)可能触发多次。这种行为和Reactv15不一致,所以标记为UNSAFE。更详细的解释参照这里(opens new window)为此,React提供了替代的生命周期钩子getSnapshotBeforeUpdate。`
render阶段
没有副作用,可能被中断
包含 constructor 、getDerivedStateFromProps 、shouldComponentUpdate、render
componentWillRecieveProps/componentWillUpdate/componentWillMount被废弃,由getDerivedStateFromProps代替
commit阶段
有副作用,可以操作dom
包含componentDidMount、componentDidUpdate、componentWilUnmount
React 16 中删除了如下三个生命周期。
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
组件挂载流程
调用ReactDom.render
进入render阶段
采用深度优先遍历算法创建fiber树
进入commit阶段
初始进入页面
constructor
getDerivedStateFromProps
render
componentDidMount
状态更新
getSnapshotBeforeUpdate(prevProps, prevState) =>
shouldComponentUpdate
render
getSnapshotBeforeUpdate =>
// 必须有返回值 返回值作为 componentDidUpdate的第三个参数可以获取
componentDidUpdate(prevProps, prevState, valueFromSnapShot) =>
有嵌套情况
import React from 'react';
import './style.css';
class Son extends React.Component {
constructor(props) {
super(props);
console.log('子组件子组件constructor ======>');
this.state = {
number: 1
};
this.sonRef = React.createRef(null);
}
static getDerivedStateFromProps(props, state) {
console.log('子组件getDerivedStateFromProps =======>', props, state);
return props;
}
componentDidMount() {
console.log('子组件componentDidMount ======>');
}
shouldComponentUpdate(nextProps, nextState) {
console.log(
'子组件shouldComponentUpdate ====>',
'nextProps',
nextProps,
'nextState',
nextState,
'this.state',
this.state
);
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// ...
console.log('子组件getSnapshotBeforeUpdate===>', prevProps, prevState);
return this.sonRef;
}
componentDidUpdate(prevProps, prevState, valueFromSnapShot) {
console.log(
'子组件componentDidUpdate =====>',
'prevProps',
prevProps,
'prevState',
prevState,
'valueFromSnapShot',
valueFromSnapShot,
'this.state',
this.state
);
}
componentWillUnmount() {
console.log('子组件componentWillUnmount=====>');
}
render() {
console.log('子组件render ========>');
return (
<div ref={this.sonRef}>
<h1>父组件props{this.props.count}</h1>
<button onClick={() => this.setState({ count: this.state.number + 1 })}>
点击子组件更新状态{this.state.number}
</button>
</div>
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
console.log('constructor ======>');
this.state = {
count: 1
};
}
static getDerivedStateFromProps(props, state) {
console.log('getDerivedStateFromProps =======>', props, state);
return props;
}
componentDidMount() {
console.log('componentDidMount ======>');
}
shouldComponentUpdate(nextProps, nextState) {
console.log(
'shouldComponentUpdate ====>',
// 'nextProps',
// nextProps,
// 'nextState',
// nextState,
'this.state',
this.state
);
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// ...
console.log('getSnapshotBeforeUpdate===>', prevProps, prevState);
}
componentDidUpdate(prevProps, prevState) {
console.log(
'componentDidUpdate =====>',
'prevProps',
prevProps,
'prevState',
prevState,
'this.state',
this.state
);
}
componentWillUnmount() {
console.log('componentWillUnmount=====>');
}
render() {
console.log('render ========>', this.state);
return (
<>
<h1>生命周期测试</h1>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
点击更新状态{this.state.count}
</button>
<Son count={this.state.count} />
</>
);
}
}
export default function App() {
return (
<div>
<h1>Hello StackBlitz!</h1>
<p>Start editing to see some magic happen :)</p>
<Parent />
</div>
);
}
getDerivedStateFromProps
getDerivedStateFromProps exists for only one purpose. It enables a component to update its internal state as the result of changes in props.
static getDerivedStateFromProps(nextprops, prestate)
- 在 React 16.3.0 版本中:在组件实例化、接收到新的 props 时会被调用
- 在 React 16.4.0 版本中:在组件实例化、接收到新的 props 、组件状态更新时会被调用
注意
- 静态方法。不属于任何实例,内部的this并不指向组件本身,this. 的任何属性和方法都不能用。
为什么getDerivedStatefromProps是静态的?
隔离组件实例访问,不能用this.setState()等一些方法,保持该方法的纯粹,它就是用来定义派生state的,除此之外不能进行任何操作
保持它是纯函数,不要产生副作用。
- 返回一个对象来更新 state,如果返回
null
则不更新任何内容 - 由上图可以知道,props更新,setState,forceUpdate会触发getDerivedStateFromProps
forceUpdate(callback)
默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 render()
方法依赖于其他数据,则可以调用 forceUpdate()
强制让组件重新渲染。
调用 **forceUpdate()**
将致使组件调用 **render()**
方法,此操作会跳过该组件的 **shouldComponentUpdate()**
。但其子组件会触发正常的生命周期方法,包括 **shouldComponentUpdate()**
方法。
getSnapshotBeforeUpdate
getSnapshotBeforeUpdate(prevProps, prevState)
替换之前的willX的生命周期,强制用户在mount阶段获取dom
getSnapshotBeforeUpdate()
在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()
。
References
https://mp.weixin.qq.com/s/G0xcaQ1KQ9cBgO3yybhDpA
https://github.com/sisterAn/blog/issues/34