- 废弃掉了三个生命周期: componentWillMount,componentWillReceiveProps,componentWillUpdate
- 新增了两个生命周期:static getDerivedStateFromProps,getSnapshotBeforeUpdate
- getDerivedStateFromProps相当于原来的componentWillMount和componentWillReceiveProps
- getDerivedStateFromProps的有时候需要配合componentDidUpdate使用。
1.代码
import React, { Component } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function fetchData() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve("获取ajax数据");
}, 2000);
});
}
class Welcome extends Component {
constructor(props) {
console.log("constructor", props);
super(props);
this.state = {
color: props.color
};
}
static getDerivedStateFromProps(nextProps, prevState) {
console.log("getDerivedStateFromProps", nextProps, prevState);
if (nextProps.color !== prevState.color) {
return {
color: nextProps.color
};
}
return null; // 1
// return {color: "orange"}; //2. 相对于componenentWillMount中的直接同步setState
}
componentDidMount() {
console.log("componentDidMount");
//3. this.setState({ color: "yellow" });
}
shouldComponentUpdate(nextProps, nextState) {
console.log("shouldComponentUpdate", nextProps, nextState);
return true;
}
getSnapshotBeforeUpdate() {
console.log("getSnapshotBeforeUpdate");
return null
}
componentDidUpdate(prevProps, prevState) {
console.log("componentDidUpdate", prevProps, prevState);
}
componentWillUnmount() {
console.log("componentWillUnmount");
}
changeColor = () => {
this.setState({ color: "#ddd" });
};
render() {
console.log("render", this.state.color);
return (
<div style={{ background: this.state.color }}>
<h1>react 旧的生命周期</h1>
<p>{this.state.color}</p>
<button onClick={this.changeColor}>内部change color</button>
</div>
);
}
}
class App extends Component {
state = {
currentColor: "red",
colorIndex: 0
};
changeColor = () => {
let colors = ["red", "yellow", "blue", "green", "pink"];
let { colorIndex } = this.state;
colorIndex = ++colorIndex % 5;
console.log(colorIndex);
this.setState({
currentColor: colors[colorIndex],
colorIndex
});
};
render() {
let { currentColor } = this.state;
return (
<div className="App">
<Welcome color={currentColor} />
<hr />
<button onClick={this.changeColor}>外部change color</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
2. 输出结果
1.直接输出
constructor {color: "red"}
getDerivedStateFromProps {color: "red"} {color: "red"}
render red
componentDidMount
2.componentDidMount中改变state
- ①在componentDidMount中改变state,即将代码注释3处打开,可见componentDidMount会重新触发一次render,注意这里没有ajax的异步请求,直接setState就会重新渲染!!!
constructor {color: "red"}
getDerivedStateFromProps {color: "red"} {color: "red"}
render red
componentDidMount
getDerivedStateFromProps {color: "red"} {color: "yellow"}
shouldComponentUpdate {color: "red"} {color: "red"}
render red
getSnapshotBeforeUpdate
componentDidUpdate {color: "red"} {color: "red"}
☆☆☆☆☆注意☆☆☆☆☆
上面在componentDidMount中setState想将子组件color变成yellow,但是最后还是渲染的red,是应为componentDidMount之后又调用了getDerivedStateFromProps ,导致下面这段代码再次执行,从而又把父组件的颜色渲染给了子组件,应为父组件颜色没变,仍然是一开始的red,所以子组件color又变成red了,第4点中改变子组件state值,一样会导致这个问题,即子组件设置setState
不变化。解决方案目前知道的有两种,一种是getDerivedStateFromProps 配合componentDidUpdate 使用。另一种是别在子组件中setState,全在父组件中来控制变量(或者在redux中管理)
if (nextProps.color !== prevState.color) {
return {
color: nextProps.color
};
}
3.改变父组件传入值,从而改变子组件state
点击父组件改变颜色按钮,改变父组件传入的props的值,查看结果
getDerivedStateFromProps => shouldComponentUpdate => render => getSnapshotBeforeUpdate => componentDidUpdate
getDerivedStateFromProps {color: "yellow"} {color: "red"}
shouldComponentUpdate {color: "yellow"} {color: "yellow"}
render yellow
getSnapshotBeforeUpdate
componentDidUpdate {color: "red"} {color: "red"}
4.改变子组件state值
点击子组件改变颜色按钮,改变子组件state值,查看结果
getDerivedStateFromProps => shouldComponentUpdate => render => getSnapshotBeforeUpdate => componentDidUpdate
getDerivedStateFromProps {color: "red"} {color: "yellow"}
shouldComponentUpdate {color: "red"} {color: "red"}
render red
getSnapshotBeforeUpdate
componentDidUpdate {color: "red"} {color: "red"}
☆☆☆☆☆注意☆☆☆☆☆
问题和上面第2点注意处一样,子组件改变state不变。