React 组件的生命周期
Posted poki
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React 组件的生命周期相关的知识,希望对你有一定的参考价值。
分为四个阶段:挂载 、更新、卸载、错误处理。
挂载阶段
当组件实例插入DOM时,其生命周期的调用顺序为:
-
construstor() 构造函数
-
static getDerivedStateFromProps(props,state) 给派生属性更新属性
-
render() 渲染界面
-
componentDidMount() 挂载完成,在此进行异步操作
1. constructor()
-
在构造函数里面初始化状态,这里不能调用
this.State()
-
通过props设置的状态称之为派生状态
-
父组件里面的props是不能直接更改的,解决方案就是设置派生状态
-
// 把父组件传递过来的属性数据传递给构造函数 constructor(props){ super(props) this.state = { a:props.n // 通过props设置的状态称之为派生状态 } }
2. static getDetivedStateFromProps()
作用:通过父组件传递过来的属性设置派生状态
-
什么时候会执行? new props setState forceUpdate
-
当初始化的时候 会执行
-
当父组件传递属性过来时 会执行
-
当状态更新时 会执行
-
-
在 return 里设置组件状态
-
一定要 return ,如果无须设置组件状态可以返回 null
-
两个参数
-
props 父组件通过设置属性传递过来的数据
-
state 组件的状态
-
static getDerivedStateFromProps(props,state){ // 返回一个对象就是设置派生状态 return { a:props.n } }
3. render()
作用:写 html 结构代码
什么时候会执行: 初始化,new props,setState(),forceUpdata()。
-
new props: 父组件传过来的属性发生变化时。
-
setState(): 自身状态更新时。
-
forceUpdate(): 强制更新,即:强制执行一遍 render()
render() { return ( <div> // 组件页面结构 </div> ) }
4. componentDidMount()
-
什么时候执行?
-
会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。
-
-
在这个函数里面执行异步操作
-
因为在这里可以操作真实DOM
-
异步操作的最终目的就是设置组件的状态
setState({})
,在这可以设置状态this.setState({})
,-
constructor() 不能 调用 this.setState()
-
static getDetivedStateFromProps() 不能获取thi
-
这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在
componentWillUnmount()
里取消订阅。你可以在
componentDidMount()
里直接调用setState()
。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在render()
两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。通常,你应该在constructor()
中初始化 state。如果你的渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理componentDidMount(){ axios.get("http://localhost:4000/list").then(res => { // 在回调中设置状态,回调函数就是异步完成后要执行的函数 this.setState({ list:res.data, name:‘‘ }) }) }
-
注意:当组件的状态或者外部传入进来的属性发生改变的时候,组件的render函数会重新执行。
更新阶段
更新阶段周期函数的执行顺序为:
-
static getDerivedStateFromProps(props,state)
-
shouldComponentUpdate(nextProps,nextState)
-
render()
-
getSnapshotBeforeUpdate(prevProps, prevState)
-
componentDidUpdate(prevProps, prevState, snapshot)
2.shouldComponentUpdate(nextProps, nextState)
作用: 当 props或state 发生变化时阻止组件的更新,即:阻止render()函数的执行。
意义:提高性能优化,减少不必要的 render() 执行行为。例如循环渲染子组件时。
阻止方法:返回 false。 只要返回false render() 函数就不会执行。
什么时候不触发:初始化的时候不会触发。forceUpdate()不会触发。
两个参数:nextProps, nextState。
-
nextProps:拿到更改后的属性值,在函数里面 this.props 拿到的是更改之前的属性
-
nextState:拿到自身状态发生改变后的状态,在函数里面 this.state 拿到的是更改之前的属性。
注:如果改变状态时使用++更改数值状态,那么nextState.a 和 this.state.a 拿到的都是更新后的值。
setState({
a:++this.state.a
}) -
这两个参数存在的意义:可以通过判断前后是否相同来决定是否更新组件(执行一遍render())。
PureComponent
作用:继承纯组件可以自动对比前后状态的更改,如果状态或属性更改了才执行 render()。这样就可以高性能了,也不用去判断,内部都已经做了处理。
defalut class index extends PureComponent {}
-
需要导入
import {PureComponent} from ‘react‘
-
纯组件里面不能再复写shouldComponentUpdate()
-
内部进行的比较是浅比较,只能比较值和地址的变化,arr[1, 2] ==> arr[1, 2, 3] 会被认为没有发生变化
-
解决不能比较数组元素发生变化的问题:给状态设置一个新的数组
let newArr = [
-
React.memo()
无状态组件的性能优化,与PureComponent相似
export default React.memo(function One(props) { let {item, index, change, } = props console.log("render") return ( <div> <label>{item.text}</label> <input type="checkbox" onChange={change.bind(this, index)} checked={item.flag}></input> </div> ) })
4. getSnapshopBeforeUpdate(prevProps, prevState)
-
必须配合 componentDidUpdate() 使用
-
什么时候触发:组件更新前(render 触发时 ==》 newprops、setState、forceUpdate )
-
必须有返回值, 返回值不能是undefined。
-
两个参数
-
prevProps: 属性更新前的属性(只要子组件被渲染一遍,就会更新属性,那么就会触发getSnapshopBeforeUpdate)
-
prevState: 状态更新前的状态
-
5. componentDidUpdate(prevProps, prevState, snapshot)
-
什么时候触发:会在更新后会被立即调用。首次渲染不会执行此方法。如果
shouldComponentUpdate()
返回值为 false,则不会调用componentDidUpdate()
。 -
三个参数
-
prevProps: 组件更新前的属性
-
prevState: 组件更新前的状态
-
snapshot: getSnapshotBeforeUpdate() 的返回值。如果getSnapshotBeforeUpdate() 没有实现则返回 undefined.
-
当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。(例如,当 props 未发生变化时,则不会执行网络请求)。
componentDidUpdate(prevProps) { // 典型用法(不要忘记比较 props): if (this.props.userID !== prevProps.userID) { this.fetchData(this.props.userID); } }你也可以在
componentDidUpdate()
中直接调用setState()
,但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。不要将 props “镜像”给 state,请考虑直接使用 props。 欲了解更多有关内容,请参阅为什么 props 复制给 state 会产生 bug。如果组件实现了
getSnapshotBeforeUpdate()
生命周期(不常用),则它的返回值将作为componentDidUpdate()
的第三个参数 “snapshot” 参数传递。否则此参数将为 undefined。
卸载阶段
componentWillUnmount()
-
什么时候执行?在这里能做什么?
会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在
componentDidMount()
中创建的订阅等。如果组件卸载了定时器确没有清除,那么定时器会一直执行。 -
卸载组件的方法:
ReactDOM.unmountComponentAtNode(document.getElementById(‘root‘)
// 设置定时器在挂载完毕这个组件生命周期函数里面设置 componentDidMount(){ this.timer = setInterval(function(){ console.log(123) },1000) } ? componentWillUnmount(){ clearInterval(this.timer) } ? render() { return ( <div> <button onClick={()=> {ReactDOM.unmountComponentAtNode(document.getElementById(‘root‘))}}>卸载组件</button> </div> ) }
以上是关于React 组件的生命周期的主要内容,如果未能解决你的问题,请参考以下文章