生命周期
组件从创建到销毁的一系列过程
挂载时阶段
- contructor(props){super(props)}构造函数,只会触发一次
- 初始化state
- 给函数提前绑定this
- 注意事项:1.必须写super()调用父类的构造函数,2.可以调用接口,但不推荐
- static getDerivedStateFromProps(props,state)
- 会触发多次,挂载与更新阶段都会触发
- 触发在挂载阶段的constructor之后,render之前,DerivedState派生state
- 参数:
props:组件最新收到的props数据
state:组件当前的state数据 - 注意事项:
1.该函数增加了static表示为类的函数,不能使用this
2.该函数必须要有返回值,返回值的内容需要一个或者null
返回对象:该对象会与当前的state合并,最终state中会包含该对象的内容
返回null:不会合并操作 - 使用场景:
当前组件的数据, 需要基于props做更新时使用,类似于vue的计算属性
- render()渲染函数,会触发多次,挂载阶段和更新阶段都会触发
- 返回一段jsx来渲染页面
- 注意事项:
1.不能调用接口,保持组件的纯粹
2.不能包含副作用的操作:操作DOM,改变数据,调用接口
- componentDidMount()挂载完成,只会触发一次
在这个钩子函数中可以:- 调用接口
- 获取组件的真实DOM
- 全局事件绑定,如:window.addEventlisten(‘scroll’)
- 订阅,如:pubsubjs或者其他模块做事件总线
- 计时器或定时器
更新时阶段
在new props,setState,forceUpdate时,就会进入更新阶段
- static getDerivedStateFromProps(props,state)
- shouldComponentUpdate(nextProps,nextState)
- 在继承React.PureComponent的组件中不能写这个钩子函数,因为这个继承已经有了类似的该功能
- 参数:
nextProps:更新后的props,当需要用旧数据与新数据做比较时,this.props就是拿到老数据
nextState:更新后的state - 用于做性能优化,控制组件是否需要更新需要有返回值,返回true需要更新,false不需要更新
- 如果调用的是forceupdate()强制更新,该生命周期钩子函数不会触发
- 如果组件继承的是PureComponent,则不要使用该生命周期
- render()在上一步返回true需要更新时,进入该钩子函数,forceUpdate触发直接进入render
- getSnapshotBeforeUpdate(prevProps,prevState),Snapshot快照
- 在组件更新之前获取当前的真实DOM的快照信息
- 参数:
prevProps更新前的props
prevState更新前的state
需要返回值,返回值会作为componentDidUpdate()的第三个参数
- componentDidUpdate(prevProps,prevState,snapshot)组件更新完成,真实DOM已经替换
这里第三个参数就是getSnapshotBeforeUpdate()的返回值
在这个钩子函数中,不要修改数据,调用接口,会导致死循环,要加上条件控制
卸载时阶段
- componentWillUnmount(){
收尾工作,解绑事件,解除定时器
比如:eventBus.off(“要取消的事件名字”,对应的处理函数)
}
Context 上下文,类似于vue的依赖注入(provide inject)
当组件层级非常深时,需要传值使用
- 另起一个js文件,引入createContext
import { createContext } from "react";
const context = createContext();
export default context;
- 在组件jsx文件中导入,
import Context from "./contexts/context";
- 长辈组件中(父组件或爷组件等高层级的组件),使用Context.Provider
class App extends React.Component {
state = {
name: "张三",
};
render() {
return (
//通过value绑定state的数据传递给儿孙组件
<Context.Provider value={this.state.name}>
<h1>App</h1>
<button
onClick={() =>
this.setState((prevState) => ({
name: prevState.name + "~",
}))
}
>
修改我的 name,我后代通过 Context 获取到的值都会跟着变
</button>
<hr />
<Hello />
</Context.Provider>
);
}
}
- 子组件以及孙子组件
//孙子组件
class Button extends React.Component {
render() {
return (
<div>
{/*
Consumer , 接受一个 函数类型的 children prop
1. 函数会自动调用,且会接收到一个参数,参数值value就是配套的 Provider 的提供值。
*/}
<Context.Consumer>
{(value) => {
return <button>Button - {value}</button>;
}}
</Context.Consumer>
</div>
);
}
}
//子组件
class Hello extends React.Component {
static contextType = Context;
render() {
return (
<div>
<h4>Hello - {this.context}</h4>
<hr />
//引入孙子组件Button
<Button />
</div>
);
}
}
类组件如何使用
1.需要通过React.createContext(defaultValue) 创建个context对象
该方法可以传递一个默认的value 的值
import { createContext } from “react”
const context = createContext(“张三”)
2.要使用的组件就直接引入该context 对象,且设置到类的contextType 属性上。
import Context from “./context”
App.contextType = Context 或在类中 static contextType = Context
3.该组件就可以通过this.context 获取到context对象的内容了。
这里创建的context是无法修改的,需要使用context的Provider组件
<context.Provider value={数据}>
<子组件>
</context.Provider>
context的Consumer组件
在子组件中
<Context.Consumer>
{(value)=>{
return {value}
}}
</Context.Consumer>
这组标签内的函数会自动执行,其中参数value就是长辈组件传下来的context.Provider的数据