react 生命周期钩子函数
老的生命周期
-
初始化阶段
// 组件将要被挂载,render 之前最后一次修改状态的机会 componentWillMount () {} // 不安全,将被新生命周期替代 // 渲染,只能访问 this.props 和 this.state,不允许修改状态和 dom 输出 render () {} // 成功 render 并渲染完成真实 dom 之后触发,可以修改 dom componentDidMount () {}
-
运行中阶段
// 子组件将要接收 props, 父组件改变 传给子组件的属性时调用 componentWillReceiveProps(nextProps) { // 不安全,将被新生命周期替代 console.log("更新前的 props", this.props) console.log("更新后的 props", nextProps) } // 组件是否需要更新,返回 true 更新;返回 false 不更新,可以用来优化组件性能 shouldComponentUpdate(nextProps, nextState) { // 更新前状态与更新后状态相同,就返回 false,不更新 if (JSON.stringify(this.state) === JSON.stringify(nextState)) return false return true } // 组件更新之前调用 componentWillUpdate(nextProps, nextState) { // 不安全,将被新生命周期替代 console.log("更新前的数据", this.state) console.log("将要更新的数据", nextState) } // 渲染,只能访问 this.props 和 this.state,不允许修改状态和 dom 输出 render () {} // 组件更新完成后调用 componentDidUpdate(prevProps, prevState) { console.log("更新前的数据", prevState) console.log("更新后的数据", this.state) }
-
销毁阶段
// 在删除组件之前进行清理操作,比如计时器和事件监听器 componentWillUnmount () {}
在老的生命周期中存在一些问题
-
componentWillMount 这个钩子函数,在 ssr 中这个方法将会被调用多次,所以会重复触发多遍,同时在这里如果绑定事件,将无法解绑,导致内存泄漏。
-
componentWillReceiveProps 这个钩子函数,在外部组件多次、频繁传入不同的 props 时,会导致产生不必要的异步请求。
-
componentWillUpdata 这个钩子函数,可以在更新前记录 dom 状态,但是如果与 componentDidUpdata 钩子函数相隔时间过长,会导致记录的状态不可信
针对以上三个钩子函数的 bug 问题,官方给了出新的生命周期钩子函数
-
getDerivedStateFromProps 钩子函数
- 作用:取代 componentWillMount 钩子函数与 componentWillReceiveProps 钩子函数
- 用法:第一次的初始化组件以及后续的更新组件时调用,返回一个对象作为新的 state,返回 null 则说明不需要在这里更新 state
import React, { Component } from 'react' class Child extends Component { state = { abc: 'abc' } render() { return ( <div> <p>child --- {this.props.title}</p> <p>{this.state.msg}---{this.state.abc}</p> </div> ) } // 初始化组件以及更新组件都会触发这个钩子函数 static getDerivedStateFromProps(props, state) { console.log(props, state) return { // 这个对象会结合之前的 state,返回一个新的 state msg: 456 } } } export default class App extends Component { state = { title: '标题' } render() { return ( <div> <p>app</p> <button onClick={() => this.setState({title: '标题2'})}> click </button> <Child title={this.state.title} /> </div> ) } }
-
getSnapshotBeforeUpdate 钩子函数
- 作用:取代 componentWillUpdata 钩子函数
- 用法:在 render 之后 componentDidUpdata 钩子之前触发,返回一个值,作为 componentDidUpdata 钩子函数的第三个参数
import React, { Component } from 'react' class Child extends Component { render () { return ( <div> <p>child---{this.props.title}</p> </div> ) } // 这个钩子函数需要与 componentDidUpdate 配合使用,不然会报警告 getSnapshotBeforeUpdate = (prevProps, prevState) => { console.log(prevProps) return 100 } componentDidUpdate(prevProps, prevState, value) { console.log(value) // 100 } } export default class App extends Component { state = { title: '标题' } render() { return ( <div> <p>app</p> <button onClick={() => this.setState({title: '标题2'})}> click </button> <Child title={this.state.title}/> </div> ) } }
react 中性能优化方案
-
shouldComponentUpdate 钩子函数,控制组件自身或者子组件是否需要更新,尤其在子组件非常多的非常多的情况下,需要进行优化。
-
PureComponent 会自动比较新 props 跟旧 props,新 state 和 旧 state,决定 shouldComponentUpdata 钩子函数返回 true,还是 false。注意:如果 state 和 props 永远不会变,那么 PureComponent 并不会比较快,因为 shallowEqual 也需要时间。
import React, { Component, PureComponent } from 'react' class Child extends PureComponent { // 继承 PureComponent 的组件会自动做性能优化 render () { return ( <div> <p>child --- {this.props.title}</p> </div> ) } } export default class App extends Component { state = { title: '标题' } render() { return ( <div> <p>app</p> <Child title={this.state.title} /> </div> ) } }