生命周期钩子
生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子
- 组件从创建到死亡它会经历一些特定的阶段
- React组件中包含一系列钩子函数(生命周期回调函数),会再特定时刻调用。
- 我们再定义组件时,会在特定的生命周期回调函数中,做特定的工作。
生命周期流程图(旧v16.8.4)
挂载时的生命周期
<script type="text/babel">
// 创建组件
class Count extends React.Component {
// 构造器
constructor(props) {
console.log("constructor");
super(props);
this.state = {
count: 0,
};
}
// 组件将要挂载的钩子
componentWillMount() {
console.log("componentWillMount");
}
// 组件挂载完毕的钩子
componentDidMount() {
console.log("componentDidMount");
}
add = () => {
let { count } = this.state;
count += 1;
this.setState({ count: count });
};
render() {
console.log("render");
return (
<div>
<h2>`当前求和为{this.state.count}`</h2>
<button onClick={this.add}>点我加一</button>
</div>
);
}
}
ReactDOM.render(<Count />, document.getElementById("test"));
</script>
更新时的生命周期 —— setState()
- shouldComponentUpdate(){ return true;}
如果写了,就必须有返回值,如果没写,React会自动给补上一个返回值为true的。
<script type="text/babel">
// 创建组件
class Count extends React.Component {
// 构造器
constructor(props) {
console.log("constructor");
super(props);
this.state = {
count: 0,
};
}
// 组件将要挂载的钩子
componentWillMount() {
console.log("componentWillMount");
}
// 组件挂载完毕的钩子
componentDidMount() {
console.log("componentDidMount");
}
// 组件将要被卸载
componentWillUnmount() {
console.log("componentWillUnmount");
}
//卸载组件按钮的回调
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById("test"));
};
// 控制组件更新的阀门
shouldComponentUpdate() {
console.log("shouldComponentUpdate");
return true;
}
// 组件将要更新的钩子
componentWillUpdate() {
console.log("componentWillUpdate");
}
//组件更新完毕的钩子
componentDidUpdate() {
console.log("componentDidUpdate");
}
add = () => {
let { count } = this.state;
count += 1;
this.setState({ count: count });
};
render() {
console.log("render");
return (
<div>
<h2>`当前求和为{this.state.count}`</h2>
<button onClick={this.add}>点我加一</button>
<button onClick={this.death}>点我消失</button>
</div>
);
}
}
ReactDOM.render(<Count />, document.getElementById("test"));
</script>
更新时的生命周期 —— forceUpdate()
- 不对状态进行任何修改,调用forceUpdate()也可以更新。不受到shouldComponentUpdate()的限制
<script type="text/babel">
// 创建组件
class Count extends React.Component {
// 构造器
constructor(props) {
console.log("constructor");
super(props);
this.state = {
count: 0,
};
}
// 组件将要挂载的钩子
componentWillMount() {
console.log("componentWillMount");
}
// 组件挂载完毕的钩子
componentDidMount() {
console.log("componentDidMount");
}
// 组件将要被卸载
componentWillUnmount() {
console.log("componentWillUnmount");
}
//卸载组件按钮的回调
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById("test"));
};
// 控制组件更新的阀门
shouldComponentUpdate() {
console.log("shouldComponentUpdate");
return true;
}
// 组件将要更新的钩子
componentWillUpdate() {
console.log("componentWillUpdate");
}
//组件更新完毕的钩子
componentDidUpdate() {
console.log("componentDidUpdate");
}
force = () => {
this.forceUpdate();
};
add = () => {
let { count } = this.state;
count += 1;
this.setState({ count: count });
};
render() {
console.log("render");
return (
<div>
<h2>`当前求和为{this.state.count}`</h2>
<button onClick={this.add}>点我加一</button>
<button onClick={this.death}>点我消失</button>
<button onClick={this.force}>点我强制刷新</button>
</div>
);
}
}
ReactDOM.render(<Count />, document.getElementById("test"));
</script>
父组件的更新流程
- 父组件一旦重新render,子组件就会响应componentWillReceiveProps()。【第一次传的不算】
class A extends React.Component {
// 初始化状态
state = {
car: "奔驰",
};
changeCar = () => {
this.setState({ car: "奥拓" });
};
render() {
return (
<div>
<div>我是A组件</div>
<button onClick={this.changeCar}>换车</button>
<B carName={this.state.car} />
</div>
);
}
}
class B extends React.Component {
// 控制组件更新的阀门
shouldComponentUpdate() {
console.log("shouldComponentUpdate");
return true;
}
// 组件将要更新的钩子
componentWillUpdate() {
console.log("componentWillUpdate");
}
//组件更新完毕的钩子
componentDidUpdate() {
console.log("componentDidUpdate");
}
// 组件将要接收新的props的钩子
componentWillReceiveProps(props) {
console.log("componentWillReceiveProps", props);
}
render() {
console.log("render");
return <div>我是B组件,接收到的车是{this.props.carName}</div>;
}
}
ReactDOM.render(<A />, document.getElementById("test"));
总结
- 初始化阶段:由React.DOM.render()出发——初次渲染
- constructor()
- componentWillMount()
- render
- componentDidMount() —— 常用
一般在这个钩子中做一些初始化的事,例如:烤漆定时器,发送网络请求,订阅消息
- 更新阶段:由组件内部this.setState()或父组件重新render触发
- shouldComponentUpdate()
- componentWillUpdate()
- render()
- componentDidUpdate()
- 卸载组件:由React.unmountComponentAtNode()出发
- componentWillUnmount() —— 常用
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
生命周期(新v17.0.1)
新版本中可以用旧的钩子,但是会有警告
- 新版本中,三个方法必须加上前缀UNSAFE_
- componentWillMount() => UNSAFE_componentWillMount()
- componentWillUpdate() => UNSAFE_componentWillUpdate()
- componentWillReceiveProps() => UNSAFE_componentWillReceiveProps()
- 新提出两个钩子:
- getDerivedStateFromProps()
- getSnapshotBeforeUpdate()
但是用的地方十分罕见
<script type="text/babel">
// 创建组件
class Count extends React.Component {
// 构造器
constructor(props) {
console.log("constructor");
super(props);
this.state = {
count: 0,
};
}
// 组件将要挂载的钩子
UNSAFE_componentWillMount() {
console.log("componentWillMount");
}
// 组件挂载完毕的钩子
componentDidMount() {
console.log("componentDidMount");
}
// 组件将要被卸载
componentWillUnmount() {
console.log("componentWillUnmount");
}
//卸载组件按钮的回调
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById("test"));
};
// 控制组件更新的阀门
shouldComponentUpdate() {
console.log("shouldComponentUpdate");
return true;
}
// 组件将要更新的钩子
UNSAFE_componentWillUpdate() {
console.log("componentWillUpdate");
}
//组件更新完毕的钩子
componentDidUpdate() {
console.log("componentDidUpdate");
}
force = () => {
this.forceUpdate();
};
add = () => {
let { count } = this.state;
count += 1;
this.setState({ count: count });
};
render() {
console.log("render");
return (
<div>
<h2>`当前求和为{this.state.count}`</h2>
<button onClick={this.add}>点我加一</button>
<button onClick={this.death}>点我消失</button>
<button onClick={this.force}>点我强制刷新</button>
</div>
);
}
}
//父组件A
class A extends React.Component {
// 初始化状态
state = {
car: "奔驰",
};
changeCar = () => {
this.setState({ car: "奥拓" });
};
render() {
return (
<div>
<div>我是A组件</div>
<button onClick={this.changeCar}>换车</button>
<B carName={this.state.car} />
</div>
);
}
}
//子组件B
class B extends React.Component {]
UNSAFE_componentWillReceiveProps(){
}
render() {
console.log("render");
return <div>我是B组件,接收到的车是{this.props.carName}</div>;
}
}
ReactDOM.render(<Count />, document.getElementById("test"));
ReactDOM.render(<Count />, document.getElementById("test"));
</script>
getDerivedStateFromProps()
- 不是给实例调用,在定义前要加static,加在类自身上,并且必须返回一个状态对象或者null
- 从props获得派生的状态,这个状态无法被改变
- 此方法适用于十分罕见的用例,即state的值在任何时候都取决于props
- 派生状态会导致代码冗余,并使组件难以维护
<script type="text/babel">
// 创建组件
class Count extends React.Component {
// 构造器
constructor(props) {
console.log("constructor");
super(props);
this.state = {
count: 0,
};
}
//若任何时候state的值在任何时候都取决于props,则可以用getDerivedStateFromProps
static getDerivedStateFromProps(props) {
console.log("getDerivedStateFromProps");
return props;
}
// 组件挂载完毕的钩子
componentDidMount() {
console.log("componentDidMount");
}
// 组件将要被卸载
componentWillUnmount() {
console.log("componentWillUnmount");
}
//卸载组件按钮的回调
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById("test"));
};
// 控制组件更新的阀门
shouldComponentUpdate() {
console.log("shouldComponentUpdate");
return true;
}
//组件更新完毕的钩子
componentDidUpdate() {
console.log("componentDidUpdate");
}
force = () => {
this.forceUpdate();
};
add = () => {
let { count } = this.state;
count += 1;
this.setState({ count: count });
};
render() {
console.log("render");
return (
<div>
<h2>`当前求和为{this.state.count}`</h2>
<button onClick={this.add}>点我加一</button>
<button onClick={this.death}>点我消失</button>
<button onClick={this.force}>点我强制刷新</button>
</div>
);
}
}
ReactDOM.render(<Count count="199" />, document.getElementById("test"));
</script>
getSnapshotBeforeUpdate()
- 在最近一次渲染输出(提交到DOM节点)之前调用,它使得组件能在发生更改之前从DOM中捕获一些信息(例如:滚动位置)。此声明周期的任何返回值将作为参数传递给componentDidUpdate()
- 必须有返回值,要么一个快照,要么一个null
- 任何值都可以作为快照值
- componentDidUpdate(preProps,preState,snapShot)可以接受三个参数,一个是之前传递的props,一个是之前的state,还有快照值
- getDerivedStateFromProps(props,state)接收当前的props和state
<script type="text/babel">
class NewsList extends React.Component {
state = {
newsArr: [],
};
componentDidMount() {
setInterval(() => {
//获取原状态
const { newsArr } = this.state;
//模拟一条新闻
const news = "新闻" + (newsArr.length + 1);
//更新状态
this.setState({ newsArr: [news, ...newsArr] });
}, 1000);
}
getSnapshotBeforeUpdate() {
return this.refs.list.scrollHeight;
}
componentDidUpdate(preProps, preState, height) {
this.refs.list.scrollTop += this.refs.list.scrollHeight - height;
}
render() {
return (
<div className="list" ref="list">
{this.state.newsArr.map((n, index) => {
return (
<div key={index} className="news">
{n}
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<NewsList />, document.getElementById("test"));
</script>
总结
- 初始化阶段:由ReactDOM.render()触发——初次渲染
- constructor()
- getDerivedStateFromProps()
- render()
- componentDidMount() —— 常用
一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
- 更新阶段:由组件内部this.setState()或父组件重新render触发
- getDerivedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
- 卸载组件:由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount() —— 常用
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息