React组件的生命周期深入理解分析
作者:花铛
组件从创建到销毁的过程,被称为组件的生命周期。
在生命周期的各个阶段都有相对应的钩子函数,会在特定的时机被调用,被称为组件的生命周期钩子。
生命周期回调函数 = 生命周期钩子函数 = 生命周期函数 = 生命周期钩子
函数式组件没有生命周期,因为生命周期函数是 React.Component 类的方法实现的,函数式组件没有继承 React.Component,所以也就没有生命周期。
<-- 容器!--> <div id="test"></div> // 创建组件 class Life extends React.Component{ state = {opacity:1} // 调用时机:组件挂载完毕 componentDidMount(){ this.timer = setInterval(() => { let {opacity} = this.state opacity -= 0.1 if(opacity <= 0) opacity = 1 this.setState({opacity}) }, 200); } //调用时机:组件将要卸载 componentWillUnmount(){ clearInterval(this.timer) } handleUnmount = ()=>{ //卸载组件 ReactDOM.unmountComponentAtNode(document.getElementById('test')) } //调用时机:初始化渲染、状态更新之后 render(){ return( <div> <h2 style={{opacity:this.state.opacity}}>我是一段透明度会变化的文字</h2> <button onClick={this.handleUnmount}>点击卸载</button> </div> ) } } //渲染组件 ReactDOM.render(<Life/>,document.getElementById('test'))
生命周期钩子(新)
新的生命周期钩子增加了 getDerivedStateFromProps 和 getSnapshotBeforeUpdate。
constructor():constructor() 构造函数在 React 组件挂载之前被调用。
如果不初始化 state 或不为事件处理函数绑定实例,则不需要写 constructor()。
不能在 constructor() 构造函数内部调用 this.setState(), 因为此时第一次 render() 还未执行,也就意味 DOM 节点还未挂载。
static getDerivedStateFromProps(nextProps, prevState):在每次调用 render() 方法之前都会被调用,在初始化和更新时都会被调用。
getDerivedStateFromProps() 第一个参数为即将更新的 props,第二个参数为上一个状态的 state,可以比较 props 和 state 来加一些限制条件,防止无用的 state 更新。
getDerivedStateFromProps() 的返回值是必须的。返回一个对象来更新 state,如果不需要更新,返回 null 即可。 getDerivedStateFromProps() 适用于 state 的值在任何时候都取决于 props 的情况。 getDerivedStateFromProps() 是一个静态函数,是放在组件身上的,而不是放在组件实例身上,因此不能使用 this。
// 之前使用 componentWillReceiveProps componentWillReceiveProps(nextProps) { if (nextProps.location.search !== this.props.location.search) { this.init() } } // 现在使用 getDerivedStateFromProps:相当于把 componentWillReceiveProps 拆分成 getDerivedStateFromProps 和 componentDidUpdate static getDerivedStateFromProps(nextProps, prevState) { const {search} = nextProps.location if (search !== prevState.search) { return { search, } } return null } componentDidUpdate(prevProps, prevState) { const {search} = this.state if (search !== prevState.search) { this.init() } }
render():render() 方法是类组件中唯一必须实现的方法,用于渲染 DOM,render() 方法必须返回 reactDOM。
在 render() 的 return 之前不能写 setState,否则会触发死循环导致内存崩溃;return 体里面是可以写的。
// Wrong render(){ this.setState({...}) return (...) } // Correct render(){ return ( <input onClick={()=>this.setState({...})} /> ) }
componentDidMount():在组件挂载后 (插入 DOM 树后) 立即调用,此生命周期是发送网络请求、开启定时器、订阅消息等的好时机,并且可以在此钩子函数里直接调用 setState()。
shouldComponentUpdate(nextProps, nextState):在组件更新之前调用,可以控制组件是否进行更新, 返回 true 时组件更新, 返回 false 则不更新。不写此生命周期钩子时默认为 true。
shouldComponentUpdate() 第一个参数是即将更新的 props 值,第二个参数是即将更新后的 state 值,可以根据更新前后的 props 或 state 来比较加一些限制条件,决定是否更新,进行性能优化。
不要在 shouldComponentUpdate 中调用 setState(),否则会导致无限循环调用更新、渲染,直至浏览器内存崩溃。
getSnapshotBeforeUpdate(prevProps, prevState):在最新的渲染数据提交给 DOM 前会调用,也就是说,在 render 之后,在 componentDidUpdate 之前调用。使得组件可以在更新之前获取快照值。不常用。
它可以使组件在 DOM 真正更新之前捕获一些信息(例如滚动位置),此生命周期返回的任何值都会作为参数传递给 componentDidUpdate(),如不需要传递任何值,那么返回 null。返回值是必须的。
componentDidUpdate(prevProps, prevState, snapshot):componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行。
包含三个参数,第一个是上一次props值。 第二个是上一次state值,第三个是“snapshot” 参数传递。
可以进行前后 props 的比较进行条件语句的限制,来进行 setState() , 否则会导致死循环。
componentWillUnmount():componentWillUnmount() 在组件即将被卸载或销毁时进行调用。此生命周期是清理定时器、取消订阅等操作的好时机。
组件的挂载流程:
- constructor
- getDerivedStateFromProps
- render
- componentDidMount
setState 更新流程:
- getDerivedStateFromProps
- shouldComponentUpdate
- render
- getSnapshotBeforeUpdate
- componentDidUpdate
组件的卸载流程: componentWillUnmount
生命周期钩子(旧)
React 从 v16.3 开始废弃 componentWillMount、componentWillReceiveProps、componentWillUpdate 三个钩子函数。在新版本中使用需要加上 UNSAFE_
前缀,否则会触发控制台的警告。
UNSAFE 不是指安全性,而是表示使用这些生命周期的代码在 React 的未来版本中更有可能出现 Bug,尤其是在启用异步渲染之后。
组件的挂载流程:
- constructor
- componentWillMount
- render
- componentDidMount
setState 更新流程:
- shouldComponentUpdate
- componentWillUpdate(组件更新之前调用)
- render
- componentDidUpdate
forceUpdate 强制更新流程:
- componentWillUpdate(组件更新之前调用)
- render
- componentDidUpdate
父组件 render 之后子组件的更新流程:
- componentWillReceiveProps(子组件接收到新的 props 之前调用,第一次接收到 props 不会调用)
componentWillReceiveProps(nextProps) { // 可以和 this.props 中的数据进行对比,以决定是否要执行某些方法 }
- shouldComponentUpdate
- componentWillUpdate(组件更新之前调用)
- render
- componentDidUpdate
组件的卸载流程:
componentWillUnmount
父子组件生命周期
当子组件自身的 state 状态改变,不会对父组件产生副作用的情况下,父组件不会进行更新,也就是不会触发父组件的生命周期。
当父组件状态变化时(不会是否更改到传给子组件的 props),会触发自身和子组件对应的生命周期。
render 以及 render 之前的生命周期,父组件先执行;
render 之后的生命周期,子组件先执行,并且是与父组件交替执行。
父子组件初始化流程:
- 父组件constructor
- 父组件getDerivedStateFromProps
- 父组件render
- 子组件constructor
- 子组件getDerivedStateFromProps
- 子组件render
- 子组件componentDidMount
- 父组件componentDidMount
子组件修改自身的 state 状态流程:
- 子组件getDerivedStateFromProps
- 子组件shouldComponentUpdate
- 子组件render
- 子组件getSnapshotBeforeUpdate
- 子组件componentDidUpdate
父组件修改 state 状态流程:
- 父组件getDerivedStateFromProps
- 父组件shouldComponentUpdate
- 父组件render
- 子组件getDerivedStateFromProps
- 子组件shouldComponentUpdate
- 子组件render
- 子组件getSnapshotBeforeUpdate
- 父组件getSnapshotBeforeUpdate
- 子组件componentDidUpdate
- 父组件componentDidUpdate
父组件卸载子组件:
// 通过点击父组件中的 [卸载 / 挂载子组件] 按钮来卸载子组件 handelToggle = () => { this.setState({ isHidden: !this.state.isHidden }) } <button onClick={this.handelToggle}>挂载/卸载子组件</button> {this.state.isHidden ? '' : <Child />>}
- 父组件getDerivedStateFromProps
- 父组件shouldComponentUpdate
- 父组件render
- 父组件getSnapshotBeforeUpdate
- 子组件componentWillUnmount
- 组件componentDidUpdate
父组件重新挂载子组件:
再次点击父组件中的 [卸载 / 挂载子组件] 按钮来挂载子组件。
- 父组件getDerivedStateFromProps
- 父组件shouldComponentUpdate
- 父组件render
- 子组件constructor
- 子组件getDerivedStateFromProps
- 子组件render
- 父组件getSnapshotBeforeUpdate
- 子组件componentDidMount
- 父组件componentDidUpdate
到此这篇关于React组件的生命周期深入理解分析的文章就介绍到这了,更多相关React组件的生命周期内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!