React组件的生命周期深入理解分析
花铛 人气:0组件从创建到销毁的过程,被称为组件的生命周期。
在生命周期的各个阶段都有相对应的钩子函数,会在特定的时机被调用,被称为组件的生命周期钩子。
生命周期回调函数 = 生命周期钩子函数 = 生命周期函数 = 生命周期钩子
函数式组件没有生命周期,因为生命周期函数是 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
加载全部内容