本章我们将讨论react旧版的生命周期钩子函数,以便更好的学习react最新版钩子函数。
react组件挂载时的钩子函数
react组件挂载时的钩子执行顺序如图
我们先看一个简单的求和案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>hello_react</title>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="./js/react.development.js"></script>
<!-- 引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="./js/react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转为js -->
<script type="text/javascript" src="./js/babel.min.js"></script>
<script type="text/babel">
// 1、创建类组件
class Count extends React.Component {
state = {
count: 0,
};
add = () => {
this.setState({
count: this.state.count + 1 });
};
render() {
return (
<div>
<h1>{
this.state.count}</h1>
<button onClick={
this.add}>点我+1</button>
</div>
);
}
}
// 渲染组件
ReactDOM.render(<Count />, document.getElementById("test"));
</script>
</body>
</html>
页面效果
现在,我们将钩子函数写入上述代码中,进行验证
class Count extends React.Component {
constructor(props) {
console.log("Count的constructor函数钩子");
super(props);
this.state = {
count: 0,
};
}
// 组价挂载前
componentWillMount() {
console.log("Count的componentWillMount函数钩子");
}
add = () => {
this.setState({
count: this.state.count + 1 });
};
render() {
console.log("Count的render函数钩子");
return (
<div>
<h1>{
this.state.count}</h1>
<button onClick={
this.add}>点我+1</button>
</div>
);
}
// 组价挂载完成
componentDidMount() {
console.log("Count的componentDidMount函数钩子");
}
}
上述代码中,我们使用了constructor,我了代码一致性,我们将state写在了constructor内部。
我们看看钩子的执行顺序
通过上图,我们可以看出组件挂载过程中,钩子函数的执行顺序是:constructor、componentWillMount、render及componentDidMount
注意,render钩子在每次页面有更新时,都会执行一次。
react组件更新时的钩子
当组件有更新时,组件也会触发一系列钩子函数
setState系列钩子
我们先看最简单的setState这条线的钩子
class Count extends React.Component {
constructor(props) {
console.log("Count的constructor函数钩子");
super(props);
this.state = {
count: 0,
};
}
// 组价挂载前
componentWillMount() {
console.log("Count的componentWillMount函数钩子");
}
add = () => {
this.setState({
count: this.state.count + 1 });
};
render() {
console.log("Count的render函数钩子");
return (
<div>
<h1>{
this.state.count}</h1>
<button onClick={
this.add}>点我+1</button>
</div>
);
}
// 组价挂载完成
componentDidMount() {
console.log("Count的componentDidMount函数钩子");
}
// 控制是否允许组件更新的钩子,需要返回一个布尔值
shouldComponentUpdate() {
console.log("组件状态更改控制钩子:shouldComponentUpdate");
return true;
}
// 组件更新前
componentWillUpdate() {
console.log("组件更新前:ComponentWillUpdate");
}
// 组件更新完成
componentDidUpdate() {
console.log("组件更新完成:componentDidUpdate");
}
}
通过下图,当组件挂载时,以此执行constructor、componentWillMount、render、componentDidMount钩子;组件state更新时,依次触发shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate钩子。
注意,shouldComponentUpdate是一个特殊钩子,是控制是否允许更新state状态值的,他需要返回一个布尔值,代表是否更新state的值
forceUpdate系列钩子
当页面有状态更改时,会触发setState系列钩子。但有时候,我们不想更改任何状态值也想上页面更新,这个时候就会触发forceUpdate系列钩子。forceUpdate系列钩子只比setState钩子少一个shouldComponentUpdate生命周期。
我们看一个demo
class Count extends React.Component {
constructor(props) {
console.log("Count的constructor函数钩子");
super(props);
this.state = {
count: 0,
};
}
// 组价挂载前
componentWillMount() {
console.log("Count的componentWillMount函数钩子");
}
add = () => {
this.setState({
count: this.state.count + 1 });
};
force = () => {
this.forceUpdate();
};
render() {
console.log("Count的render函数钩子");
return (
<div>
<h1>{
this.state.count}</h1>
<button onClick={
this.add}>点我+1</button>
<button onClick={
this.force}>强制更新</button>
</div>
);
}
// 组价挂载完成
componentDidMount() {
console.log("Count的componentDidMount函数钩子");
}
// 控制是否允许组件更新的钩子,需要返回一个布尔值
shouldComponentUpdate() {
console.log("组件状态更改控制钩子:shouldComponentUpdate");
return true;
}
// 组件更新前
componentWillUpdate() {
console.log("组件更新前:ComponentWillUpdate");
}
// 组件更新完成
componentDidUpdate() {
console.log("组件更新完成:componentDidUpdate");
}
}
上述代码,我们通过this.forceUpdate()强制更新了页面,以此触发了componentWillUpdate、render、componentDidUpdat钩子
父组件触发render系列钩子
我们实现一个嵌套的父子组件,父组件有两个按钮,子组件用来显示父组件的选中按钮。
<script type="text/babel">
// 1、创建类组件
class Parent extends React.Component {
state = {
text: "" };
choose = (type) => {
if (type === "1") this.setState({
text: "父组件选择了按钮一" });
if (type === "2") this.setState({
text: "父组件选择了按钮二" });
};
render() {
return (
<div>
<button
onClick={
() => {
this.choose("1");
}}
>
按钮1
</button>
<button
onClick={
() => {
this.choose("2");
}}
>
按钮2
</button>
<Child text={
this.state.text}></Child>
</div>
);
}
}
// 渲染组件
class Child extends React.Component {
render() {
const {
text } = this.props;
return <div>{
text ? text : "什么都没选中"}</div>;
}
}
ReactDOM.render(<Parent />, document.getElementById("test"));
</script>
上述代码中我们在父组件中定义了按钮选中的状态文本值state.text,然后传递给子组件。子组件通过props接受。
当父组件切换按钮导致子组件props值发生变化时子组件触发一些列钩子
// 渲染组件
class Child extends React.Component {
// 父组件触发子组件props更新特有的钩子
componentWillReceiveProps() {
console.log("组件接受新的props前:componentWillReceiveProps");
}
// 控制是否允许组件更新的钩子,需要返回一个布尔值
shouldComponentUpdate() {
console.log("子组件状态更改控制钩子:shouldComponentUpdate");
return true;
}
// 组件更新前
componentWillUpdate() {
console.log("子组件更新前:ComponentWillUpdate");
}
// 组件更新完成
componentDidUpdate() {
console.log("子组件更新完成:componentDidUpdate");
}
render() {
console.log("子组件的render函数钩子");
const {
text } = this.props;
return <div>{
text ? text : "什么都没选中"}</div>;
}
}
如图,componentWillReceiveProps是子组件props值发生变化时,所特有的钩子。
钩子函数总结
React组件的生命周期可以分为三个阶段:
挂载阶段(Mounting):组件被创建并插入到DOM中
由ReactDom.render()触发--初次渲染
- constructor
- componnetWillMount
- render
- componentDidMount(常用)
这个钩子做一些初始化的事情,例如开启定时器、发送请求。订阅消息等
- 更新阶段(Updating):组件被重新渲染
- shouldComponentUpdate
- componentWillUpdate
- rende
- componentDidUpdate
- 卸载阶段(Unmounting):组件被从DOM中移除
- componnetWillUnmount
这个钩子做一些收尾的事情,例如关闭定时器、取消订阅消息等