文章目录
一、笔者述 :
现在的时间是 2019年11月2日,React
生命周期较以前也有了很大变化。
但是为了更清楚直观的理解当前 React 的生命周期,笔者会从更新之前版本的 React 生命周期说起 :
并且笔者不是大佬,暂时还不会去从源码角度去揭示或者验证写什么,此篇文章仅仅是供自己以后查看和供小白们参考。
二、React 生命周期 ( 以前版本 )
1. 生命周期方法 :
- getDefaultProps
- getInitalState
- constructor
- componentWillMount
- render
- componentDidMount
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- componentDidUpdate
- componentWillUnMount
2. 工作流程 [正常情况下 - 5 个场景]:
- 场景一 : 仅仅只是渲染了节点元素,并没有通过事件或者异步任务来更新 state 时,其经过生命周期的流程是这样的 :
getDefaultProps -> getInitalState -> constructor -> componentWillMount -> render -> componentDidMount
用 UML 建模来表示就是这样 :
- 场景二 : 在场景一的基础上通过触发事件或者异步任务等,更新了 state 其经过生命周期的流程是这样的 :
handleEvent
-> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
用 UML 建模来表示就是这样 :
这里有个比较有趣的生命周期方法,就是 shouldComponentUpdate
,因为该方法需要有返回值(布尔类型),也就是说返回 true
则继续向下执行 componentWillUpdate
然后 render
,如果返回 false
则不会向下继续执行 componentWillUpdate
,而是直接保持原来的状态,你会发现界面的 UI 也没有变化。
所以因为 shouldComponentUpdate
如此有趣,在这里我们或许可以通过属性判断来优化 React 组件在运行过程中的性能!
- 场景三 : 通过事件或者异步任务等执行了
UnMountComponentAtNode(container)
而卸载 React 组件
其经过生命周期的流程是这样的 :
handleEvent
/ componentDidMount / componentDidUpdate -> componentWillUnMount
须知 UnMountComponentNodeAt(container)
方法中的参数是一个真实的表示当前 React 根组件
对应的 dom
节点。
至于为什么在 componentDidMount
和 componentDidUpdate
中也可以执行这个操作,因为就拿 React 整个的生命周期来说只有 componentDidMount【组件已挂载】
和 componentDidUpdate【组件已更新】
这两个周期函数在运行的时候当时的 React 组件都已经被映射成真实的 dom
元素了,所以才可能获取得到真实的 dom
节点,尽管直接操作 dom
是不被提倡的,但是在特定条件下我们也别无选择不是吗 ?
用 UML 建模来表示就是这样 :
- 场景四 : 父组件引发了 props 值的变动
其经过生命周期的流程是这样的 :
componentWillReceiveProps -> shouldComponentUpdate -> componentWillUpdate -> componentDidUpdate
用 UML 建模来表示就是这样 :
所以说白了 componentWillReceiveProps
仅仅是会在所被注入的 props
变动的时候才会执行,并且之后继续走 shouldComponentMount
的逻辑。
-
场景五 : 调用
forceUpdate()
导致跳过shouldComponentUpdate
直接继续执行componentWillUpdate
、render
和componentDidUpdate
。
用 UML 建模来表示就是这样 :
为什么调用forceUpdate
会跳过shouldComponentUpdate
呢 ?
-1). 简单的通过翻译便可知晓一部分原因 :force : 译为【暴力;力量】
,should : 译为【应该;应当】
。
所以当我们打算执行"确定"
了,我们还多次一举的去执行"不确定"
做什么呢 ?
-2). 如果页面上有些数据不是通过 state 挂载的,就是一些普通的变量,但是你也想通过触发事件去更改页面上的值,此时你在handleClick
中无论怎么改值,可就是不会render
,相应的页面上那个有纯变量渲染的值也是不会变的咯 ~ 。所以这种场景下就可以调用forceUpdate
进行强制更新,届时你会发现页面上那个由纯变量渲染的值,也变成了你在handleClick
中改的值。目的也就达到了。此时我们涉及的仅仅是普通变量,不涉及state
,所以也没有必要去走shouldComponentUpdate
。 -
所以以上
5
个场景基本上把整个 以前版本 的React
生命周期囊括在内了。 所以下面贴出上述5
个场景使用的代码
以及gif
参考动图。
-1). 场景一的配套代码以及动图 :
代码 :
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
// App 组件
class App extends Component {
static propTypes() {
console.log("propTypes ...");
}
static defaultProps() {
console.log("defaultsProps ...");
}
// React 组件的构造器
constructor(props) {
super(props);
console.log("constructor ...");
// 初始化 state
this.state = {
name: "FruitJ"
};
}
componentWillMount() {
console.log("componentWillMount ...");
}
componentDidMount() {
console.log("componentDidMount ...");
}
render() {
console.log("render ...");
return (
<div>
<span>{ this.state.name }</span>
</div>
);
}
componentWillReceiveProps(nextProps, nextContext) {
console.log("componentWillReceiveProps ...");
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("shouldComponentUpdate ...");
return true;
}
componentWillUpdate(nextProps, nextState, nextContext) {
console.log("componentWillUpdate ...");
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate ...");
}
componentWillUnmount() {
console.log("componentWillUnmount ...");
}
}
export default App;
动图 :
-2). 场景二的配套代码以及动图 :
代码 :
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
// App 组件
class App extends Component {
static propTypes() {
console.log("propTypes ...");
}
static defaultProps() {
console.log("defaultsProps ...");
}
// React 组件的构造器
constructor(props) {
super(props);
console.log("constructor ...");
// 初始化 state
this.state = {
name: "FruitJ"
};
}
componentWillMount() {
console.log("componentWillMount ...");
}
componentDidMount() {
console.log("componentDidMount ...");
}
handleClick = () => {
// 更新 state
this.setState({
name: "LJ"
});
console.log("handleClick ...");
};
render() {
console.log("render ...");
return (
<div>
<span>{ this.state.name }</span>
<button onClick = { this.handleClick }>切换</button>
</div>
);
}
componentWillReceiveProps(nextProps, nextContext) {
console.log("componentWillReceiveProps ...");
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("shouldComponentUpdate ...");
return true;
}
componentWillUpdate(nextProps, nextState, nextContext) {
console.log("componentWillUpdate ...");
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate ...");
}
componentWillUnmount() {
console.log("componentWillUnmount ...");
}
}
export default App;
动图 :
-3). 场景三的配套代码以及动图 :
代码 :
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
let temp = 9;
// App 组件
class App extends Component {
static propTypes() {
console.log("propTypes ...");
}
static defaultProps() {
console.log("defaultsProps ...");
}
// React 组件的构造器
constructor(props) {
super(props);
console.log("constructor ...");
let a = "ssassss";
// 初始化 state
this.state = {
name: "FruitJ"
};
}
componentWillMount() {
console.log("componentWillMount ...");
}
componentDidMount() {
console.log("componentDidMount ...");
}
handleClick = () => {
// 更新 state
this.setState({
name: "LJ"
});
console.log("handleClick ...");
};
handleRemoveClick = (ev) =>{
ReactDOM.unmountComponentAtNode(ev.target.parentNode.parentNode);
};
render() {
console.log("render ...");
return (
<div>
<span>{ this.state.name }</span>
<button onClick = { this.handleClick }>切换</button>
<button onClick = {this.handleRemoveClick}>remove ReactDOM</button>
</div>
);
}
componentWillReceiveProps(nextProps, nextContext) {
console.log("componentWillReceiveProps ...");
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("shouldComponentUpdate ...");
return true;
}
componentWillUpdate(nextProps, nextState, nextContext) {
console.log("componentWillUpdate ...");
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate ...");
}
componentWillUnmount() {
console.log("componentWillUnmount ...");
}
}
export default App;
动图 :
-4). 场景四的配套代码以及动图 :
代码 :
父组件 :
import React, { Component } from 'react';
import SubComponent from './SubComponent';
export default class Index extends Component {// 定义组件
constructor(props) {
super(props);
this.state = {
name: "FruitJ"
};
console.log("Parent Component's constructor ...");
}
componentWillMount() {
console.log("Parent Component's componentWillMount ...");
}
componentDidMount() {
console.log("Parent Component's componentDidMount ...");
}
handleChangeName = () => {
this.setState({
name: "LJ"
})
};
render() {
return (
<div>
<SubComponent name = { this.state.name }
handleChangeName = { this.handleChangeName }
/>
</div>
);
}
componentWillReceiveProps(nextProps) {
console.log("Parent Component's componentWillReceiveProps ...");
}
// 此处的 nextState 指向的是此次 state
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("Parent Component's shouldComponentUpdate ...");
return true;
}
// 此处的 nextState 指向的是此次 state
componentWillUpdate(nextProps, nextState) {
console.log("Parent Component's componentWillUpdate ...");
}
// 此处的 prevState 指向的是此次 state 中的上一个 state
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("Parent Component's componentDidUpdate ...");
}
componentWillUnmount() {
console.log("Parent Component's componentWillUnmount ...");
}
}
子组件 :
import React, { Component } from 'react';
export default class SubComponent extends Component {
constructor(props) {
super(props);
console.log("Sub Component's constructor ...");
}
componentWillMount() {
console.log("Sub Component's componentWillMount ...");
}
componentDidMount() {
console.log("Sub Component's componentDidMount ...");
}
handleClick = () => {
this.props.handleChangeName();
};
render() {
return (
<div>
<span>{ this.props.name }</span>
<button onClick = { this.handleClick }>切换</button>
</div>
);
}
// 此处的 nextProps 指向的是此次的 props
componentWillReceiveProps(nextProps, nextContext) {
console.log("Sub Component's componentWillReceiveProps ...");
}
// 此处的 nextProps 指向的是此次的 props
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("Sub Component's shouldComponentUpdate ...");
return true;
}
// 此处的 nextProps 指向的是此次的 props
componentWillUpdate(nextProps, nextState) {
console.log("Sub Component's componentWillUpdate ...");
}
// 此处的 prevProps 指向的是上一次的 props
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("Sub Component's componentDidUpdate ...");
}
}
动图 :
-5). 场景五的配套代码以及动图 :
代码 :
调用 forceUpdate()
之前 :
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
let temp = 9;
// App 组件
class App extends Component {
static propTypes() {
console.log("propTypes ...");
}
static defaultProps() {
console.log("defaultsProps ...");
}
// React 组件的构造器
constructor(props) {
super(props);
console.log("constructor ...");
// 初始化 state
this.state = {
name: "FruitJ"
};
}
componentWillMount() {
console.log("componentWillMount ...");
}
componentDidMount() {
console.log("componentDidMount ...");
}
handleClick = () => {
// 更新 state
this.setState({
name: "LJ"
});
console.log("handleClick ...");
};
handleRemoveClick = (ev) =>{
ReactDOM.unmountComponentAtNode(ev.target.parentNode.parentNode);
};
handleChangeNum = () => {
temp = 66;
// this.forceUpdate();
};
render() {
console.log("render ...");
return (
<div>
<span>{ this.state.name }</span>
<button onClick = { this.handleClick }>切换</button>
<button onClick = {this.handleRemoveClick}>remove ReactDOM</button>
<span>{ temp }</span>
<button onClick = { this.handleChangeNum }>切换</button>
</div>
);
}
componentWillReceiveProps(nextProps, nextContext) {
console.log("componentWillReceiveProps ...");
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("shouldComponentUpdate ...");
/*console.log(nextProps);
console.log(nextState);
console.log(nextContext);
console.log("-- end --");*/
return true;
}
componentWillUpdate(nextProps, nextState, nextContext) {
console.log("componentWillUpdate ...");
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate ...");
}
componentWillUnmount() {
console.log("componentWillUnmount ...");
}
}
export default App;
是无法更新由纯变量渲染的值的。
动图 :
但是如果调用 forceUpdate()
,页面上由纯变量渲染的值发生了变化。
针对上面贴出的代码,将 // forceUpdate(); -- 去掉注释 --> forceUpdate();
即可。
动图 :
- 最后附上两张笔者绘制的
React 生命周期 (以前版本)
的流程图,两张表述的意思一致只不过绘制思路不同。
-1).
-2).
三、React 生命周期 ( 当前版本 )
React 当前版本的生命周期的改动比较大。
是将 componentWillMount
、componentWillUpdate
和 componentWillReceiveProps
三个生命周期方法去掉,取而代之的是 static getDerivedStateFromProps
和 getSnapshotBeforeUpdate
方法。没错这里 getDerivedStateFormProps
是一个静态方法。
推出此 2 个生命周期方法而废黜原来那 3 个生命周期方法的原因 :
一年多来,React团队一直在努力实现异步渲染。上个月,Dan在JSConf Iceland上的演讲中,展示了一些令人兴奋的异步渲染解锁新可能性。现在,我们想与您分享在使用这些功能时所学到的一些经验教训,以及一些有助于启动异步渲染准备组件的方法。
我们学到的最大的经验教训之一是,我们的某些旧组件生命周期倾向于鼓励不安全的编码实践。他们是:
componentWillMount
componentWillReceiveProps
componentWillUpdate
这些生命周期方法经常被误解和巧妙地滥用。此外,我们预计它们的潜在滥用可能会在异步渲染方面带来更多问题。因此,在即将发布的版本中,我们将为这些生命周期添加“ UNSAFE_”前缀。(在这里,“不安全”不是指安全性,而是表示使用这些生命周期的代码在React的未来版本中更有可能出现错误,尤其是在启用异步渲染后。)
---------- 引自 : 布莱恩·沃恩(Brian Vaughn)React 的官方 blog
笔者谈谈个人的理解【仅供参考】 :
相比于 Vue
的生命周期,笔者认为 React
的生命周期有些冗余与复杂,并且就像上面说的有的周期方法甚至还会存在一些隐患 :
一 一 道来 :
- React 【以前版本】的
componentWillMount
这个周期函数的存在让笔者觉得没有意义,因为如果你是企图在组件Mount
之前就拿到这个异步数据的话,在componentWillMount
里面搞是完全没有意义的。
即使是在组件Mount
之前异步请求数据,其也会在render
后被返回。
譬如说 : 如果子组件中某个需要渲染的值是来源于父组件注入的,那么如果父组件注入的这个值在更新的时候是在componentWillMount
中异步获取的话,恰好网络堵塞,就可能导致一种情况,子组件会长时间拿不到想要的值,如果子组件中要是再拿这个做一些操作,例如判断等 … 直接就会导致结果偏差。
用代码和动图来说明一下 : 【子组件要拿父组件的值做判断,及时拿到弹出yes
,反之弹出no
】
代码 :
父组件 :
import React, { Component } from 'react';
import SubComponent from './SubComponent';
export default class Index extends Component {// 定义组件
constructor(props) {
super(props);
this.state = {
name: "FruitJ"
};
console.log("Parent Component's constructor ...");
}
componentWillMount() {
console.log("Parent Component's componentWillMount ...");
fetch("../resource/data.json")
.then((res) => {
return res.json();
})
.then((data) => {
console.log("--------");
console.log(data);
setTimeout(() => {
this.setState({
name: data.animalName
})
}, 3000);
})
.catch((err) => {
console.error(err)
});
}
componentDidMount() {
console.log("Parent Component's componentDidMount ...");
}
handleChangeName = () => {
this.setState({
name: "LJ"
})
};
render() {
return (
<div>
<SubComponent name = { this.state.name }
handleChangeName = { this.handleChangeName }
/>
</div>
);
}
componentWillReceiveProps(nextProps) {
console.log("Parent Component's componentWillReceiveProps ...");
}
// 此处的 nextState 指向的是此次 state
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("Parent Component's shouldComponentUpdate ...");
return true;
}
// 此处的 nextState 指向的是此次 state
componentWillUpdate(nextProps, nextState) {
console.log("Parent Component's componentWillUpdate ...");
}
// 此处的 prevState 指向的是此次 state 中的上一个 state
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("Parent Component's componentDidUpdate ...");
}
componentWillUnmount() {
console.log("Parent Component's componentWillUnmount ...");
}
}
子组件 :
import React, { Component } from 'react';
export default class SubComponent extends Component {// 定义组件
constructor(props) {
super(props);
console.log("Sub Component's constructor ...");
this.state = {
name: "Linux"
};
}
componentWillMount() {
console.log("Sub Component's componentWillMount ...");
}
componentDidMount() {
this.props.name === "tiger" ? alert("yes"): alert("no");
console.log("Sub Component's componentDidMount ...");
}
handleClick = () => {
this.props.handleChangeName();
};
render() {
return (
<div>
<span>{ this.props.name }</span>
<button onClick = { this.handleClick }>切换</button>
<span>{ this.state.name }</span>
</div>
);
}
// 此处的 nextProps 指向的是此次的 props
componentWillReceiveProps(nextProps, nextContext) {
console.log("Sub Component's componentWillReceiveProps ...");
}
// 此处的 nextProps 指向的是此次的 props
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("Sub Component's shouldComponentUpdate ...");
return true;
}
// 此处的 nextProps 指向的是此次的 props
componentWillUpdate(nextProps, nextState) {
console.log("Sub Component's componentWillUpdate ...");
}
// 此处的 prevProps 指向的是上一次的 props
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("Sub Component's componentDidUpdate ...");
}
}
data.json :
{
"animalName": "tiger"
}
动图 :
-
- React 【以前版本】的
componentWillUpdate
这个周期函数笔者认为稍有疏忽就可能出现一些问题,如果这里你不小心更新了state
的话,对不起等待浏览器内存溢出吧【只不过 React 直接抛出了异常,结束了循环调用】,原因很简单根据React 【以前版本】
的生命周期流程思考 : 这一轮的更新操作走到了componentWillUpdate
的时候又setState
了一下,走完一圈还是会回到此函数,重蹈覆辙,直至耗尽内存。React 在这强行抛出异常某些方面是为了防止出现这种情况。
用代码和动图来说明一下 :
代码 :
- React 【以前版本】的
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
let temp = 9;
// App 组件
class App extends Component {
static propTypes() {
console.log("propTypes ...");
}
static defaultProps() {
console.log("defaultsProps ...");
}
// React 组件的构造器
constructor(props) {
super(props);
console.log("constructor ...");
// 初始化 state
this.state = {
name: "FruitJ",
animalName: "temp"
};
}
componentWillMount() {
console.log("componentWillMount ...");
}
componentDidMount() {
console.log("componentDidMount ...");
}
handleClick = () => {
// 更新 state
this.setState({
name: "LJ"
});
console.log("handleClick ...");
};
handleRemoveClick = (ev) =>{
ReactDOM.unmountComponentAtNode(ev.target.parentNode.parentNode);
};
handleChangeNum = () => {
temp = 66;
this.forceUpdate();
};
render() {
console.log("render ...");
return (
<div>
<span>{ this.state.name }</span>
<button onClick = { this.handleClick }>切换</button>
<button onClick = {this.handleRemoveClick}>remove ReactDOM</button>
<span>{ temp }</span>
<button onClick = { this.handleChangeNum }>切换</button>
{ this.state.animalName }
</div>
);
}
componentWillReceiveProps(nextProps, nextContext) {
console.log("componentWillReceiveProps ...");
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("shouldComponentUpdate ...");
return true;
}
componentWillUpdate(nextProps, nextState, nextContext) {
console.log("componentWillUpdate ...");
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate ...");
}
componentWillUnmount() {
console.log("componentWillUnmount ...");
}
}
export default App;
-
- React 【以前版本】的
componentWillReceiveProps
这个周期函数就与上面布莱恩·沃恩(Brian Vaughn)在 React 的 blog
中说的那样,与一些其他的生命周期函数结合起来在 React 整个生命周期中会使程序变得更加复杂,组件难以维护。
- React 【以前版本】的
1. 生命周期方法
- getDefaultProps
- getInitalState
- static getDerivedStateFormProps
- render
- componentDidMount
- shouldComponentUpdate
- getSnapshotBeforeUpdate
- componentDidMount
- componentWillUnMount
2. 工作流程 [正常情况下 - 5 个场景]:
- 场景一 : 仅仅只是渲染了节点元素,并没有通过事件或者异步任务来更新 state 时,其经过生命周期的流程是这样的 :
getDefaultProps -> getInitalState -> constructor -> getDerivedStateFromProps -> render -> componentDidMount
用 UML 建模来表示就是这样 :
- 场景二 : 在场景一的基础上通过触发事件或者异步任务等,更新了 state 其经过生命周期的流程是这样的 :
handleEvent
-> getDerivedStateFromProps -> shouldComponentUpdate -> getSnapshotBeforeUpdate -> componentDidUpdate
用 UML 建模来表示就是这样 :
- 场景三 : 通过事件或者异步任务等执行了
UnMountComponentAtNode(container)
而卸载 React 组件
其经过生命周期的流程是这样的 :
handleEvent
-> componentWillUnMount
用 UML 建模来表示就是这样 :
- 场景四 : 父组件引发了 props 值的变动
其经过生命周期的流程是这样的 :
getDerivedStateFromProps -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> getSnapshotBeforeUpdate【父组件】-> componentDidUpdate
用 UML 建模来表示就是这样 :
- 场景五 : 调用
forceUpdate()
导致跳过shouldComponentUpdate
直接继续执行render
、getSnapshotBeforeUpdate
和componentDidUpdate
。
用 UML 建模来表示就是这样 :
- 所以以上
5
个场景基本上把整个 当前版本 的React
生命周期囊括在内了。 所以下面贴出上述5
个场景使用的代码
以及gif
参考动图。
-1). 场景一的配套代码以及动图 :
代码 :
import React, { Component } from 'react';
import ReactDOM from "react-dom";
export default class NewComponentLifeCycle extends Component {
constructor(props) {
super(props);
console.log();
this.state = {
name: "FruitJ",
age: 21
};
}
// 此处的 state 指向的是此次 state
static getDerivedStateFromProps(props, state) {
console.log("getDerivedStateFromProps ...");
return null;
}
componentDidMount() {
console.log("componentDidMount ...");
}
render() {
console.log("render ...");
return (
<div>
<span>{ this.state.name }</span>
</div>
);
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("shouldComponentUpdate ...");
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log("getSnapshotBeforeUpdate ...");
return "Hello World!";
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate ...");
console.log(snapshot);
}
componentWillUnmount() {
console.log("componentWillUnmount ...");
}
}
动图 :
-2). 场景二的配套代码以及动图 :
代码 :
import React, { Component } from 'react';
import ReactDOM from "react-dom";
export default class NewComponentLifeCycle extends Component {
constructor(props) {
super(props);
console.log();
this.state = {
name: "FruitJ",
age: 21
};
}
// 此处的 state 指向的是此次 state
static getDerivedStateFromProps(props, state) {
console.log("getDerivedStateFromProps ...");
return null;
}
componentDidMount() {
console.log("componentDidMount ...");
}
handleClick = () => {
console.log("handleClick ...");
this.setState({
name: "LJ"
});
};
render() {
console.log("render ...");
return (
<div>
<span>{ this.state.name }</span>
<button onClick = { this.handleClick }>切换</button>
</div>
);
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("shouldComponentUpdate ...");
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log("getSnapshotBeforeUpdate ...");
return "Hello World!";
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate ...");
console.log(snapshot);
}
componentWillUnmount() {
console.log("componentWillUnmount ...");
}
}
动图 :
-3). 场景三的配套代码以及动图 :
代码 :
import React, { Component } from 'react';
import ReactDOM from "react-dom";
export default class NewComponentLifeCycle extends Component {
constructor(props) {
super(props);
console.log();
this.state = {
name: "FruitJ",
age: 21
};
}
// 此处的 state 指向的是此次 state
static getDerivedStateFromProps(props, state) {
console.log("getDerivedStateFromProps ...");
return null;
}
componentDidMount() {
console.log("componentDidMount ...");
}
handleRemoveClick = (ev) => {
ReactDOM.unmountComponentAtNode(ev.target.parentNode.parentNode);
};
render() {
console.log("render ...");
return (
<div>
<button onClick = { this.handleRemoveClick }>remove</button>
</div>
);
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("shouldComponentUpdate ...");
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log("getSnapshotBeforeUpdate ...");
return "Hello World!";
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate ...");
console.log(snapshot);
}
componentWillUnmount() {
console.log("componentWillUnmount ...");
}
}
动图 :
-4). 场景四的配套代码以及动图 :
代码 :
import React, { Component } from 'react';
import NewComponentLCSub from './NewComponentLCSub';
import ReactDOM from "react-dom";
export default class NewComponentLifeCycle extends Component {
constructor(props) {
super(props);
console.log();
this.state = {
name: "FruitJ",
age: 21
};
}
// 此处的 state 指向的是此次 state
static getDerivedStateFromProps(props, state) {
console.log("getDerivedStateFromProps ...");
return null;
}
componentDidMount() {
console.log("componentDidMount ...");
}
handleChangeAge = ()=> {
this.setState({
age: 22
});
};
render() {
console.log("render ...");
return (
<div>
<NewComponentLCSub age = { this.state.age }
handleChangeAge = { this.handleChangeAge }
/>
</div>
);
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("shouldComponentUpdate ...");
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log("getSnapshotBeforeUpdate ...");
return "Hello World!";
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate ...");
console.log(snapshot);
}
componentWillUnmount() {
console.log("componentWillUnmount ...");
}
}
-5). 场景五的配套代码以及动图 :
代码 :
import React, { Component } from 'react';
import ReactDOM from "react-dom";
let temp = 9;
export default class NewComponentLifeCycle extends Component {
constructor(props) {
super(props);
console.log();
this.state = {
name: "FruitJ",
age: 21
};
}
// 此处的 state 指向的是此次 state
static getDerivedStateFromProps(props, state) {
console.log("getDerivedStateFromProps ...");
return null;
}
componentDidMount() {
console.log("componentDidMount ...");
}
handleUpdateClick = () => {
temp = 66;
this.forceUpdate();
};
render() {
console.log("render ...");
return (
<div>
<span>{ temp }</span>
<button onClick = { this.handleUpdateClick }>forceUpdate</button>
</div>
);
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log("shouldComponentUpdate ...");
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log("getSnapshotBeforeUpdate ...");
return "Hello World!";
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate ...");
console.log(snapshot);
}
componentWillUnmount() {
console.log("componentWillUnmount ...");
}
}
- 最后附上一张笔者绘制的
React 生命周期 (当前版本)
的流程图。
四、迁移
React
更换生命周期,应该会有一批项目逐步的向新版本上来迁移,如果工程量比较大的,也不用着急 ! 因为 React
官方在新发布的 React
版本中以前版本的生命周期函数还是可以使用的
!
没错,即使不加 UNSAFE_
前缀也是可以使用的,但是 React
官方还是会建议在使用以前的周期函数最好加上 UNSAFE_
前缀标识一下,这样不仅仅是与潮流同进,也是为了以后自己迁移自己项目的时候可以很清楚分辨出哪些是需要重构的。
当前的 React 版本虽然支持 以前版本 与 当前版本的 React 周期函数,但是不建议混用,只是为了让咱们提前熟悉并且让咱们有个逐步过渡的时间。
六、总述
React
是笔者刚刚接触的框架,本篇文章真的只是浅显的入个门,还有很多内容没有说,比如父子组件之间的生命周期的流程,但这些笔者认为就不需要摆出来说一会了,因为毫无疑问,父组件必须等待响应着子组件,仅此而已 ! 而且废黜了这三个生命周期函数在一定程度上使 React
组件使用起来更加的清爽并且减少了一些因为异步或是循环调用等引起的一些比较极端而又可笑的事情发生。
七、忠告
- React 定义组件的时候除了路由组件等其他有特殊需求的以外,最好都定义为无状态组件【也就是纯函数】,这样性能会好一些。React 所提倡的就是多用无状态组件,甚至于说
Hooks
就可以将有状态组件变为无状态组件。 - React 组件的嵌套层级越少越好。嵌套过多就可能 render 不到数据。
- React 使用 React 周期函数前要了解每个周期函数的特点和作用,在合理的周期函数中做合理的事情。
- 定期关注
React conf
。
笔者浅显的用代码跑了一遍流程将其分析一顿并记录在案,能力有限难免有所疏漏,如有谬误还请指出 !
参考链接 :
-1). React数据获取为什么一定要在componentDidMount里面调用?
-2). 组件的生命周期(运行阶段和销毁阶段)以及事件处理函数
-3). React.unmountComponentAtNode is not a function
-4). componentWillReceiveProps详解(this.props)状态改变检测机制
-6). React生命周期详解
-7). React 生命周期
-8). react生命周期
-9). 添加链接描述
-10). react基本原理及性能优化
-11). React 避免重渲染
-12). forceUpdate setState有什么区别
-13). React总结(四)-- refs和forceUpdate
-14). Vue与React两个框架的区别和优势对比