react 组件的生命周期
前言
在开发模式下,你可能会发现在组件第一次初始话的时候或者时更新的时候,对应的生命周期会出现运行两次的情况,这是因为在开发模式下,react使用了<React.StrictMode>组件,你可以直接在根目录下的index.tsx中注释掉他
生命周期图鉴
生命周期列表
constructor(props):
介绍:构造函数,组件加载时最先执行的生命周期钩子函数
执行时机:组件首次渲染时会执行
接收参数:props 由父级传递的props
static getDerivedStateFromProps(props,state)
介绍:当组件的state和props改变时执行的方法
执行时机:组件首次渲染以及组件更新时执行
接收参数:props 组件接收到的props副本,state组件当前state副本
返回值:必须要有返回值,且返回值必须为null 或 {}对象,返回为null的时候,视图会按照原有的props和state渲染,但返回值为{}的时候,会将其与state合并,并将最新的state作为本次视图渲染的依据
shouldComponentUpdate(nextProps,nextState)
介绍:组件即将更新之前执行的方法,可以通过return值决定组件是否更新渲染,但是即便组件没有更新渲染,state和props的改动还是存在,只是没有视图更新;这块可以用来做性能优化的东西
执行时机:组件更新时执行
接收参数:nextProps 组件接收的Props,nextState 组件当前的state
返回值:返回一个boolean类型的值,如果是false,则组件更新到此为止,后续的渲染逻辑将不会执行
render
介绍:组件渲染函数,这是组件中唯一要实现的方法
执行时机:组件首次渲染和组件更新时会触发
接收参数:无
返回值:返回一个元素作为渲染模板
componentDidMount
介绍:组件第一次挂载时执行生命周期钩子函数
执行时机:组件首次渲染时执行
接收参数:无
getSnapshotBeforeUpdate(prevProps,prevState)
介绍:组件渲染更新提交到真实dom之前生命周期钩子函数;在此处,已经可以访问更新后的ref,但是更新后的渲染结果仍未提交到真实dom,真实dom仍然是旧的。
执行时机:组件更新时执行
接收参数:组件此时的props和state
返回值:在此方法内返回的任何值,都会被componentDidUodate接收
componentDidUpdate(prevProps,prevState,snapshot)
介绍:组件更新后生命周期钩子函数;
执行时机:组件更新完成后执行
接收参数:prevProps为组件props、prevState为组件state、snapshot为组件getSnapshotBeforeUpdate中return的值
componentWillUnmount
介绍:销毁前调用,在这个时候组件的一切功能都是可以正常使用的,但是在此调用setState,组件永远不会更新,因为在此此方法执行之后,组件将进行销毁
执行时机:组件销毁前调用
接收参数:无
过时的生命周期方法 这些声明周期虽然仍然有效,但是不推荐使用
UNSAFE_componentWillMount()
UNSAFE_componentWillReceiveProps()
UNSAFE_componentWillUpdate()
详细信息
constructor
构造函数react 实例话第一步就是执行这个方法,在这里你可以定义state的初始数据。这个方法可以不定义,但是如果你定义之后,就必须在内部使用super()方法,这是es6的规范
render
这个钩子函数虽然是组件的渲染方法,但并不是真正意义上的把元素渲染成dom的方法,在它之后还有一个把元素渲染成dom的步骤,这一步只是return一个元素对象,这个并不是组件的执行渲染功能的函数,
它的返回值是一个这样的react 元素对象,react就是最终通过它去生成dom对象。它是唯一一个react.Componet 类中必须实现的方法
componentDidMount
组件渲染完成并且挂载在dom上之后调用,这个类似与vue的mounted,者意味着这一步组件中的元素都已经转话成真实的dom,我们可以在这里进行dom操作
它可以访问this
并且不携带参数
e的值为undefined
shouldComponentUpdate
组件即将更新时触发,这个生命周期钩子在getDerivedStateFromProps之后,在render之前调用,通过return false或者true 来决定是否更新组件。
这个组件在提升性能方面非常有用,假设一个父组件中存在10个子组件,那么当父组件state或者props改变时,即便子组件没有变更,也会重新渲染,这样白白浪费了渲染开销,所以可以在子组件中的sholdComponentUpdate中判断state或者props是否发生改变,然后决定子组件是否重新渲染
这个方法接受两个参数nextProps 更新后的props nextState 更新后的state
getSnapshotBeforeUpdate
当元素最近一次渲染输出(既是当数据更新,触发react重新渲染组件之后,在把新渲染的组件挂载在dom之前)触发,这个钩子函数你应该极少使用。
getSnapshotBeforeUpdate(prevProps, prevState) { //这个方法必须要和componentDidUpdate方法一起使用 console.log(this);//可以访问this // 不推荐在此处使用setState,虽然仍可以使用 return {a: 415463564}; //在这里return的值,会传递给componentDidUpdate钩子函数的第三个参数 }
componentDidUpdate
componentDidUpdate(prevProps, prevState, snapshot) { console.log(prevProps);//更新之前的props console.log(prevState);//更新之前的state console.log(snapshot);//getSnapshotBeforeUpdate生命周期中return的值 console.log(this.state);//这里仍然可以获取this //值得一提的是在这里尽量不要掉用setState(),不然有可能会造成无限更新的情况发生 //因为在这一步react已经完成更新了,所以不能像shouComponentUpdate一下修改prevProps或者是prevState来触发视图更新 }
static getDerivedStateFromProps()
在第一次进入,和发生更新的时候(setState,props更新或者调用forceUpdate)都会触发这个生命周期钩子,并且是在render方法之前调用。同时通过return值,我们可以改变最后的渲染结果。(return的值会直接同步至state中,比如在state中有一个index属性,它的值为1,而你在此方法内返回{index:99},那么最后渲染的值为99,但是不建议在这里直接改变state,我们应当遵循react的setState改变原则)。ps:在这里无法访问this
static getDerivedStateFromProps(props, state) { console.log(props, state); state.idx = 180; //只要在此方法内改变props 或者state中的值,那么最终的渲染结果,就以此为准。即便return 为null return null; }
一些api
setState
setState是发起一个更新组件的请求,而非立即更新,它不会立即改变state和立即更新组件。为了提高更新效率,react不会对每一次的改变立即更新,而是形成一个更新队列,批量更新。这样就避免了很多无用的更新。
不要再组件更新的钩子函数中使用setState(),因为即便state没有发生任何变化,此方法也会促使视图进行更新。所以不要在会重复触发的,组件更新生命周期钩子函数中:shouldComponentUpdate、render、getSnapshotBeforeUpdate、componentWillUpdate使用此方法,有可能会造成无限次数的数据更新
componentDidMount() { for (let i = 0; i < 100; i++) { this.setState({idx: i++}); } //最终只会触发一次componentDidUpdate
console.log(this.state.idx) //打印结果为state在constructor 定义初始值 1
}
setState可接收不同的参数
1.接收一个回调函数
this.setState((state, props) => { //state和props 参数是目前组件的的最新的state,props。但是它仍不是此回调函数 return之后的state值 return {idx: '12345'} //return的值会与state进行浅合并,只有在return语句执行之后,组件的state才会进行更新 })
2.接收一个对象和一个回调函数,如果你想立即获取改变后的state值,可以使用这个方法
//通过第一个参数对象修改state,第二个回调函数参数会在componentDidUpdate之后执行 this.setState({idx: e}, function () { console.log(this.state); })
forceUpdate 强制组件重新更新
this.state.idx=999; //强制组件重新渲染,回调函数将在componentDidUpdate之后执行 this.forceUpdate(function () { console.log('强制执行')// })