1、React组件生命周期
组件的生命周期是指,组件对象从创建到死亡所经历的特定的阶段,函数式组件中包含一系列钩子函数(生命周期回调函数),在特定的时刻会自动调用
。
全称:生命周期函数或者是生命周期钩子,本质就是组件内的一些方法。
概念:生命周期函数指在某一时刻组件会自动调用执行的函数
2、完成挂载阶段——ComponentDidMount
执行顺序:(均自动执行)
(1)constructor 构造器在组件调用时首次执行,目的是为了给组件实例化对象身上做初始化赋值(this)
(2)render (组件渲染页面,state值
发生改变就会触发render重新调用,n+1次)
(3)ComponentDidMount (将组件挂载到root根容器元素对象身上)
父构造 —> 父render —> 子构造 —> 子render —> 子完成挂载 —> 父完成挂载
【应用:重点
】:定时器、ajax请求(axios)、操作DOM元素、订阅频道(兄弟组件之间的通信)
【注】我们希望一打开页面,页面上就挂载着…
【注】为什么可以操作DOM元素:页面一打开,已经转换为了真实DOM元素
3、更新阶段——ComponentDidUpdate
只有子组件状态值更新:
子render —> 子ComponentDidUpdate(不会对父组件产生影响)
父组件中状态值更新,且嵌套调用子组件时:
父render —> 子render —> 子更新 —> 父更新
【应用】:状态值改变、组件接收到新的Props
4、即将卸载阶段——ComponentWillUnMount
当每一个类组件中,有内容更改
时,都会自动触发卸载阶段的钩子函数。
只有一个组件内容更改时:
自己的构造 —> 自己的render —> 自己的卸载 —> 自己的挂载 (将之前的内容卸载之后,挂载一个新的)
父组件中内容更改,且嵌套调用子组件时:
父构造 —> 父render —> 子构造 —> 子render —> 父卸载 —> 子卸载 —> 子挂载 —> 父挂载
【应用】:清除定时器 、取消订阅
5、案例——定时器
6、案例——评论列表
7、Hook
钩子,本质就是函数,能够在函数组件中使用状态
和生命周期函数
的功能。
【注】Hook基本完全替代了类组件的语法,后面的React项目就完全是函数式组件了。
(1)useState
用来定义状态数据,可以多次调用,可产生多个状态数据。
import React , { useState } from 'react';
//函数式组件是没有实例化对象的,所以在函数内不能出现this这样的语法
export default function Counter() {
//useState(状态数据),状态数据中可以存放Number、String、Boolean、Array
//useState方法返回的是一个数组,
//数组的第一个元素:状态数据(useState方法传过来的实参)
//数组的第二个元素:更新状态值的函数结构体(类似于setState方法)
//数组的解构
let [num, setNum] = useState(100);
let addCount = function () {
num++;
//将状态值用setNum函数重新设置
setNum(num);
}
return (
<div>
<p>计数器:{num}</p>
<button onClick={addCount}>点击+1</button>
</div>
)
}
(2)useRef
功能和类式组件中的createRef()方法相似
,可以帮助我们在函数式组件中方便获取真实的DOM元素对象。
【注】ref是虚拟DOM元素的属性,但是使用ref是为了获取所在的真实DOM元素对象。
import React, { useRef } from 'react'
export default function InputValue() {
let unameIpt = useRef();
let showIptValue = function () {
console.log(unameIpt.current.value);
}
return (
<div>
<p>用户名:<input type="text" ref={unameIpt} /></p>
<button onClick={showIptValue}>点击获取输入框的内容</button>
</div>
)
}
(3)useEffect
useEffect是一个高阶函数,可以在一个组件中多次使用
,相当于componentDidMount(组件挂载完成),
componentDidUpdate(组件更新完成) 和 componentWillUnmount(组件将要卸载之前)
的组合
useEffect方法可以传递两个参数:
第一个参为函数结构,必填
第二个参数可为数组,选填
import React, { useState, useRef, useEffect } from 'react'
export default function MyComponent() {
//1、第一个参数是函数结构,第二个参数是空数组 ===> 表示ComponentDidMount 组件挂载完成
useEffect(() => {
console.log('组件挂载完成了1');
}, []);
useEffect(() => {
console.log('组件挂载完成了2');
}, []);
useEffect(() => {
console.log('组件挂载完成了3');
}, []);
//一打开页面,组建完成挂载,自动一次执行这三条语句
//2-1、第一个是函数结构,不传递第二个参数 ===> 表示表示ComponentDidMount + ComponentDidUpdate
// 即:组件挂载完成以及组件状态更新
useEffect(() => {
console.log('组件挂载完成 & 组件更新完成');
})
//组件挂载完成会执行一次,组件每次更新状态值也会执行一次
let [num, setNum] = useState(100);
let [isLogin, setisLogin] = useState(true);
//2-2、第一个是函数结构,第二个是非空数组,数组中传入state的状态数据 ===> 当这个状态数据被更新时才执行回调函数
//【注】数组的参数如果没有任何值的话,空数组,表示什么状态数据都不更新,回调函数不执行
useEffect(() => {
console.log('当islogin状态值发生改变时,组件挂载完成&组件更新完成')
}, [isLogin])
//3、模拟ComponentwillUnmount
//在脚手架中当尝试修改组件之后,react会将组件先卸载,然后再来一个新的重新挂载
//在useEffect方法中返回一个函数
useEffect(() => {
console.log('组件即将被卸载......');
})
let addCount = () => {
num += 10;
setNum(num);
}
let changeLogin = () => {
isLogin = !isLogin;
setisLogin(isLogin);
}
return (
<div>
<p>计数器:{num}</p>
<button onClick={addCount}>点我+10</button>
<hr />
<p>登录状态:{isLogin ? '已登录' : '滚去登录'}</p>
<button onClick={changeLogin}>切换登录状态</button>
</div>
)
}
【注意点】:
useEffect方法的第一个参数的函数是一个同步函数,不接收async
参数,(原因是如果设置了async,返回值就成了promise对象,非一个函数了)
如果想要在useEffect()方法中添加异步代码,需要在函数中在单独声明一个函数
useEffect(() => {
//函数声明
async function main() {
let res = await 100;
}
//函数调用
main();
})