组件实例从被创建到被销毁的过程称为组件的生命周期。react只有class组件才有生命周期,函数组件只能通过hooks去模拟
class组件
已废弃的生命周期
react16 class组件三个生命周期已废弃
- componentWillMount(将要挂载)
- componentWillReceiveProps (props改变时)
- componentWillUpdate (将要更新)
原因:在React16的Fiber架构中,调和过程有可能会多次执行will周期,不再是一次执行,失去了原有的意义。 此外,多次执行,在周期中如果有setState或dom操作,会触发多次重绘,影响性能,也会导致数据错乱
挂载阶段
生命周期 | 时机 | 常用场景 |
---|---|---|
constructor | 初始化 | 初始化组件的state |
static getDerivedStateFromProps() | props改变时 | 监听props改变,不常用 |
render | 渲染 | 必用 |
componentDidMount | 挂载后 | 数据请求,订阅等操作 |
注意:super 调用了父类的构造函数来去实例化子类本身。 如果用到了constructor就要写super(),是用来初始化this的,可以绑定事件到this上, 如果在constructor中要使用this.props,就必须给super加参数:super(props)。
更新阶段
生命周期 | 时机 | 常用场景 |
---|---|---|
static getDerivedStateFromProps | props改变时 | 监听props改变,不常用 |
shouldComponentUpdate | 组件准备更新前 | 根据参数props和state,返回true或false,来控制组件是否需要重新render,常用于组件性能优化 |
render | 渲染 | 必用 |
getSnapshotBeforeUpdate | render后更新到页面之前 | 会将返回值作为componentDidUpdate的第三个参数 |
componentDidUpdate | 组件更新后 | 监听变量改变 |
如果在componentDidUpdate中直接调用 this.setState,必须包裹在一个条件语句中,否则会导致死循环。
卸载阶段
生命周期 | 时机 | 常用场景 |
---|---|---|
componentWillUnmount | 组件卸载时 | 清楚定时器,取消订阅,清理无效dom |
错误处理
生命周期 | 时机 | 常用场景 |
---|---|---|
componentDidCatch | 组件报错时 | 监听错误处理,不白屏 |
函数组件
函数组件本身没有生命周期,但它可以通过useEffect这个hook来模拟几个常用的生命周期功能
有两个参数,第一个是回调函数(必传),第二个是依赖项数组
第二个参数决定了回调函数的执行时机
模拟componentDidMount
第二个参数传入空数组,只会在组件初次渲染完成执行一次回调
代码语言:javascript复制1 useEffect(()=>{
2 console.log("俺只会在组件第一次渲染完成时执行一回!");
3 },[])
模拟componentDidUpdate
不传第二个参数,组件每次更新都会执行一次回调
代码语言:javascript复制1 useEffect(()=>{
2 console.log("组件更新一次我就执行一次");
3 })
不要在回调里setState,会死循环
模拟componentWillUnmount
第二个参数传入空数组,第一个参数回调函数里再return一个函数,这个函数会在组件销毁时执行
代码语言:javascript复制1 useEffect(()=>{
2 return ()=>{
3 console.log("俺只会在组件销毁时时执行!");
4 }
5 },[])
监听变量改变
第二个参数,依赖项数组放入变量。当检测到变量改变时,才会执行回调
代码语言:javascript复制1 useEffect(()=>{
2 console.log("当变量a或者b改变时,我就会执行!");
3 },[a,b])
依赖项变化的判定,是使用浅比较。对于基本类型,比较值是否变化。对于引用类型,比较指针的指向是否变化