(16)React 进阶——⑥ React 生命周期函数(上):弄懂所有“生命周期函数” | React 基础理论实操
转载请注明出处,未经同意,不可修改文章内容。
🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。
涉及面试题:
1. 组件生命周期的不同阶段是什么?
2. React 生命周期方法有哪些?
3. 在 React v16 中的错误边界是什么?
4. 在 React v15 中如何处理错误边界?
5. 在 componentWillMount() 方法中使用 setState() 好吗?
6. 在 mounting 阶段生命周期方法的执行顺序是什么?
7. 在 React v16 中,哪些生命周期方法将被弃用?
8. 生命周期方法 getDerivedStateFromProps() 的目的是什么?
9. 生命周期方法 getSnapshotBeforeUpdate() 的目的是什么?
10. 在组件类中方法的推荐顺序是什么?
11. 如何在调整浏览器大小时重新渲染视图?
12. 如何监听状态变化?
13. 如何每秒更新一个组件?
14. 为什么不能在 componentWillUnmount 中调用 setState() 方法?
15. 当组件重新渲染时顺序执行的方法有哪些?
编号:[react_16]
1 Initialization
“生命周期函数”是指:在某一时刻,“组件”会自动调用并执行的函数。
“生命周期函数”是针对“组件”而言的,每一个“组件”都可以有以下“过程”中所有的“生命周期函数”:
接下来,我们结合 TodoList,按程序执行的“过程”,分阶段把“生命周期函数”讲清楚。 ❗️为了便于讲解,请将 TodoList 里的代码同步至《React 入门:⑥ TodoList 代码优化》中的版本。
1️⃣Initialization
-
含义:初始化过程;
-
TodoList 中的代码实现:
/*
🚀constructor 就是我们“初始化”的位置!我们会在这里去定义 state、去接收 props。
❓但,constructor 是不是一个“生命周期函数”呢?
答:
它符合“生命周期函数”的定义——在某一时刻,“组件”会自动调用并执行的函数。
所以,从某方面来说,我们可以把它理解为“生命周期函数”。
但是,constructor 不是 React 所独有的,它是 ES6 语法中自带的一个函数。
故,严格来说,我们不把它归类到 React 的“生命周期函数”里。
*/
constructor(props) {
super(props);
this.state = {
inputValue: "",
list: []
};
}
2 mounting
2️⃣mounting
-
含义:组件“挂载”到页面上的过程;
-
TodoList 中的代码实现:
import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem";
import "./style.css";
class TodoList extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: "",
list: []
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleBtnClick = this.handleBtnClick.bind(this);
this.handleItemDelete = this.handleItemDelete.bind(this);
}
componentWillMount() { /*
2️⃣-①:这个“生命周期函数”是在“组件”
即将被“挂载”到页面的时刻自动执行;
❓什么是“挂载”?
答:“挂载”指“组件”第一次被放在页面的时候。
❗️故:一般来说,一个组件在页面上展示的时候,
componentWillMount 只会执行一次(“挂载”的这个阶段)!
*/
console.log("componentWillMount")
}
render() { // 2️⃣-②:这个“生命周期函数”是去做“组件”的“挂载”;
console.log("parent render")
return(
<Fragment>
<div>
<label htmlFor="insertArea">请输入要进行的事项:</label>
<input
id="insertArea"
className="input"
value={this.state.inputValue}
onChange={this.handleInputChange}
/>
<button onClick={this.handleBtnClick}>
提交
</button>
</div>
<ul>
{this.getTodoItem()}
</ul>
</Fragment>
)
}
componentDidMount() { /*
2️⃣-③:这个“生命周期函数”是在“组件”
被“挂载”到页面之后自动执行;
❗️一般来说,一个组件在页面上展示的时候,
componentDidMount 也只会执行一次(“挂载”的这个阶段)!
🏆请一定注意这个特点,下下篇文章,
我们会利用“只执行一次”这个特性,去进行 AJAX 数据的请求。
*/
console.log("componentDidMount")
}
getTodoItem() {
return this.state.list.map((item, index) => {
return(
<TodoItem
key={index}
content={item}
index={index}
itemDelete={this.handleItemDelete}
/>
)
})
}
handleInputChange(e) {
const value = e.target.value
this.setState(() => ({
inputValue: value
}))
}
handleBtnClick() {
this.setState((prevState) => ({
list: [...prevState.list, prevState.inputValue],
inputValue: ""
}))
}
handleItemDelete(index) {
this.setState((prevState) => {
const list = [...prevState.list]
list.splice(index, 1)
return {list}
})
}
}
export default TodoList;
看下页面的控制台(当组件成功“挂载”到页面后,再进行相关操作时, componentWillMount
和 componentDidMount
都不再执行,但 render
会执行):
3 Updation
3️⃣Updation
-
含义:组件“更新”的过程,即“数据”——state、props 发生变化的时候,页面的“更新”会被执行的过程;
-
TodoList 中的代码实现:
❗️我们先讲 props 和 states 发生变化时,它们所共有的“生命周期函数”的执行逻辑。
import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem";
import "./style.css";
class TodoList extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: "",
list: []
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleBtnClick = this.handleBtnClick.bind(this);
this.handleItemDelete = this.handleItemDelete.bind(this);
}
componentWillMount() {
console.log("componentWillMount")
}
render() {
console.log("parent render")
return(
<Fragment>
<div>
<label htmlFor="insertArea">请输入要进行的事项:</label>
<input
id="insertArea"
className="input"
value={this.state.inputValue}
onChange={this.handleInputChange}
/>
<button onClick={this.handleBtnClick}>
提交
</button>
</div>
<ul>
{this.getTodoItem()}
</ul>
</Fragment>
)
}
componentDidMount() {
console.log("componentDidMount")
}
shouldComponentUpdate() { /*
3️⃣-①:这个“生命周期函数”是在“组件”
被“更新”之前,会被自动执行;
*/
console.log("shouldComponentUpdate")
}
getTodoItem() {
return this.state.list.map((item, index) => {
return(
<TodoItem
key={index}
content={item}
index={index}
itemDelete={this.handleItemDelete}
/>
)
})
}
handleInputChange(e) {
const value = e.target.value
this.setState(() => ({
inputValue: value
}))
}
handleBtnClick() {
this.setState((prevState) => ({
list: [...prevState.list, prevState.inputValue],
inputValue: ""
}))
}
handleItemDelete(index) {
this.setState((prevState) => {
const list = [...prevState.list]
list.splice(index, 1)
return {list}
})
}
}
export default TodoList;
在页面控制台查看一下打印出来的信息:
❌注意看页面的“警告”: shouldComponentUpdate
函数需要返回一个“布尔值”。
为什么呢?从单词结构就可以看出,这是在“询问”我们:组件需要被“更新”吗?
- true:更新,继续下一个“生命周期函数”的执行,页面产生相应的反馈;
- false:不更新,后边的“生命周期函数”不再执行,页面不产生任何的反馈。
💡一般情况下,这里都是 true
,我们下篇文章会讲解 false
的用法(用于提高“组件”的性能)。
回到 TodoList.js
文件,继续讲解:
import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem";
import "./style.css";
class TodoList extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: "",
list: []
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleBtnClick = this.handleBtnClick.bind(this);
this.handleItemDelete = this.handleItemDelete.bind(this);
}
componentWillMount() {
console.log("componentWillMount")
}
render() { /*
3️⃣-③:“生命周期函数”render 会执行,根据变化了的“数据”,
重新“更新”页面;
*/
console.log("parent render")
return(
<Fragment>
<div>
<label htmlFor="insertArea">请输入要进行的事项:</label>
<input
id="insertArea"
className="input"
value={this.state.inputValue}
onChange={this.handleInputChange}
/>
<button onClick={this.handleBtnClick}>
提交
</button>
</div>
<ul>
{this.getTodoItem()}
</ul>
</Fragment>
)
}
componentDidMount() {
console.log("componentDidMount")
}
shouldComponentUpdate() { /*
3️⃣-①:这个“生命周期函数”是在“组件”
被“更新”之前,会被自动执行;
*/
console.log("shouldComponentUpdate")
return true
}
componentWillUpdate() { /*
3️⃣-②:这个“生命周期函数”是在“组件”
被“更新”之前,shouldComponentUpdate 询问之后,
且得到 true 的“答复”后,才自动执行;
*/
console.log("componentWillUpdate")
}
componentDidUpdate() { /*
3️⃣-④:这个“生命周期函数”是在“组件”
被“更新”完成之后,会自动执行。
*/
console.log("componentDidUpdate")
}
getTodoItem() {
return this.state.list.map((item, index) => {
return(
<TodoItem
key={index}
content={item}
index={index}
itemDelete={this.handleItemDelete}
/>
)
})
}
handleInputChange(e) {
const value = e.target.value
this.setState(() => ({
inputValue: value
}))
}
handleBtnClick() {
this.setState((prevState) => ({
list: [...prevState.list, prevState.inputValue],
inputValue: ""
}))
}
handleItemDelete(index) {
this.setState((prevState) => {
const list = [...prevState.list]
list.splice(index, 1)
return {list}
})
}
}
export default TodoList;
返回页面控制台查看打印信息:
接着,我们来看看 3️⃣中,props 和 states 不一样的部分—— componentWillReceiveProps
。
❓这个“生命周期函数”特殊在哪呢? 答:
TodoList
是一个“顶层组件”,它并没有接收任何 props
。接收 props
最多的是 TodoItem
组件。即,这个“生命周期函数”只对拥有 props
参数的 TodoItem
组件生效。
打开 TodoItem.js
文件:
import React, { Component } from "react";
class TodoItem extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
render() {
const {content} = this.props
return(
<div onClick={this.handleClick}>
{content}
</div>
)
}
handleClick() {
const {itemDelete, index} = this.props
itemDelete(index)
}
componentWillReceiveProps() { /*
❗️❗️❗️这个“生命周期函数”要执行,需同时满足以下条件:
①:这个组件要从父组件接收“参数”;
②:如果这个组件“第一次”存在于父组件中,这个“生命周期函数”不会执行;
③:如果这个组件之前已经存在于父组件中,这个“生命周期函数”才会执行。
*/
console.log("child componentWillReciveProps")
}
}
export default TodoItem;
返回页面控制台查看打印信息:
4 Unmounting
4️⃣Unmounting
-
含义:把“组件”从页面上去除的过程;
-
TodoList 中的代码实现(打开
TodoItem.js
文件):
import React, { Component } from "react";
class TodoItem extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
render() {
const {content} = this.props
return(
<div onClick={this.handleClick}>
{content}
</div>
)
}
handleClick() {
const {itemDelete, index} = this.props
itemDelete(index)
}
componentWillReceiveProps() {
console.log("child componentWillReciveProps")
}
componentWillUnmount() { /*
❗️❗️❗️这个“生命周期函数”是在“组件”
即将被程序从页面上剔除时,会自动执行。
*/
console.log("child componentWillUnmount")
}
}
export default TodoItem;
返回页面控制台查看打印信息:
祝好,qdywxs ♥ you!
转载自:https://juejin.cn/post/7290732297427058743