1.生命周期函数
1.1 16版本及以前的
初始化constructor
-->将要渲染componentWillMount
--->已经渲染componentDidMount
--->组件接受传递数据componentWillReceiveProps
----> 是否要更新(shouldComponentUpdate)
---->将要更新componentWillUpdate
---->更新过程render
---->已经更新componentDidUpdate
--->卸载componentWillUnmount
// 组件数据来源 组件本身的状态state(可读可写) 和传递过来props(只读)/*
react16生命周期函数:分为三个过程 对应的9个钩子函数1 挂载过程 constructor(初始化类似于beforeCreate),componentWillMount(渲染前,类似于vue的beforeMount)、componentDidMount(渲染后,类似于mounted)2 更新过程 componentWillReceiveProps(将要接受传递数据) 、 shouldComponentUpdate(组件是否要更新)、 componentWillUpdate(组件将要更新)、render(更新过程)、 componentDidUpdate(组件更新之后)3 卸载过程 componentWillUnmount() 卸载过程
*/class S1 extends React.Component{ constructor(props){// 1 组件构造函数 创建组件对象,构造器里面的this就是指向正在创建的组件对象,state在此处进行初始化,不能访问this.props,这个函数执行完之后this.props才会有值,console.log("1 组件初始化数据的触发,此处不能访问this.Props")super()this.state={age:10,b:""}}//WARNING! To be deprecated in React v17. Use componentDidMount instead.componentWillMount() {// 不能在此钩子获取DOM节点console.log("2 组件将要渲染的时候触发,此处不能获取DOM节点",document.getElementById("d1"))}componentDidMount() { // 在此处可以获取DOM节点console.log("3 组件已经渲染完毕的时候触发",document.getElementById("d1"))}//WARNING! To be deprecated in React v17. Use new lifecycle static getDerivedStateFromProps instead.// 组件将要接受传递数据更新时候触发,需要在此钩子函数里面根据传递的数据是否更新组件(对比更新前后的数据,如果一样了,这时候不需要更新,如果不一样了,需要更新)// 如果点击修改sex 如果修改了sex改成了女 是更新,再点击由女变成女 不需要更新// nextProps 更新之后的数据// this.props 更新之前的数据componentWillReceiveProps(nextProps) {console.log("4 组件将要接受传递数据触发",nextProps,this.props)if(nextProps.bool!=this.props.bool){// 需要更新 把更新之后数据赋值给本组件的状态bthis.setState({b:nextProps.bool },()=>{// b数据更新成功了 setState是一个异步修改// 发请求,根据在使用组件的时候传递数据不一样,根据数据发请求或者进行渲染})}}shouldComponentUpdate(nextProps, nextState) { console.log("5 组件是否要更新")// console.log(this.props.bool,nextProps.bool);console.log(this.state.b,nextState.b);// 对比组件接收到的状态是否一致,一致不需要更新if (this.state.b != nextState.b) return trueelse return false}//WARNING! To be deprecated in React v17. Use componentDidUpdate instead.componentWillUpdate(nextProps, nextState) {console.log("6 组件将要更新")}componentDidUpdate(prevProps, prevState) {console.log("7 组件已经更新")}componentWillUnmount() {console.log("8 组件将要卸载")}render() {console.log("render 更新过程")return({this.state.age} --{this.state.b}{/**/})}
}class Father extends React.Component{constructor(props){super()this.state = {sex:"男"}}render(){return( )}
}// 16的渲染函数是 参数1渲染的组件 参数2渲染的节点
ReactDOM.render( ,document.getElementById("app")
)
1.2 17及以后的生命周期函数
新的钩子函数8个
1 挂载过程
constructor(初始化状态)
---componentWillMount(**删除)
componentDidMount(渲染完毕)
2 更新过程
getDerivedStateFromProps(从props更新状态,要有返回对象;返回对象是组件状态的更新 ,与this.setState一样中的对象一样,不要更改的话返回null)(**componentReceivedProps改名)、
shouldComponentUpdate(是否要更新,需要有返回值是一个布尔值) 、
getSnapshotBeforeUpdate(组件更新前,要有返回对象,返回值是对象)(**componentWillUpdate改名)
render(更新)、
componentDidUpdate(已经更新)
3 卸载过程
/*
新的钩子函数8个
1 挂载过程 constructor(初始化状态) componentWillMount(删除)componentDidMount(渲染完毕)
2 更新过程 getDerivedStateFromProps(从props更新状态,要有返回值)(componentReceivedProps改名)、shouldComponentUpdate(是否要更新) 、getSnapshotBeforeUpdate(组件更新前,要有返回值)(componentWillUpdate改名) render(更新)、componentDidUpdate(已经更新)
3 卸载过程 componentWillUnmount 卸载前
*/
class S1 extends React.Component{constructor(props){console.log("1 组件初始化数据的触发")super()this.state={ i1:""}}// react17 以及更高的版本把componentWillMount(将要渲染的钩子函数)写的业务路径放在componentDidMount(以及渲染的钩子函数中)// componentWillMount() {}componentDidMount() { console.log("2 组件渲染完毕的钩子函数")}// 更新过程 // componentWillReceiveProps(nextProps) {}// componentWillReceiveProps 被取代了 替换成了getDerivedStateFromProps(从props获取状态)// derived 获取;static getDerivedStateFromProps(props, state) {console.log("3 组件从props中获取数据时候调用,可以调用的多次,初始化的时候也会调用一次",props,state)if(props.id!=state.i1){// 当传递数据和当前状态不一样时候,需要把传递数据更新到组件状态上// -----------------------------------------------------------// 注意:::返回对象是组件状态的更新 ,把状态的i1更新成props.idreturn {i1:props.id }}return null // 如果传递数据和当前状态一样 不用更新状态}shouldComponentUpdate(nextProps, nextState) { // nextState 更新之后的状态// this.state.i1console.log("4 组件是否要更新",nextProps,nextState,this.state)// 下面四种方式都可以提升渲染效率// if(nextProps.id != this.state.i1){if(nextState.i1 != this.props.id){// if(nextState.i1 != this.state.i1){ // if(nextProps.id != this.props.id){ return true // true 组件要更新; false 组件不更新}return false}//WARNING! To be deprecated in React v17. Use componentDidUpdate instead. // componentWillUpdate(nextProps, nextState) {}// 将要更新的函数componentWillUpdate 被替代了,换成了getSnapshotBeforeUpdate()// snapshot 快照getSnapshotBeforeUpdate (prevProps, prevState){console.log("5 组件在最终更新前触发")return null}componentDidUpdate(prevProps, prevState) {console.log("6 组件更新之后触发")}componentWillUnmount() { console.log("7 组件更将要卸载的时候触发")}render() {return({this.state.i1})}
}class Father extends React.Component{constructor(props){super()this.state = {id:1}}render(){return( )}
}const root = ReactDOM.createRoot(document.getElementById("app")).render( )
3 扩展,更改生命周期函数的原因。
componentWillReceiveProps为啥被替换为getDerivedStateFromProps???
因为强制开发者去对比props对象和state对象,而不是直接对比props和this.props,
防止开发者会去操作this.props,组件自身的状态将变得不可预测;
老版本对比this.props和nextProps;新版本使用props传递的数据与state自身定义的状态进行对比;
旧的React中componentWilReceiveProps方法是用来判断前后两个props是否相同,如果不同,则将新的props更新到
相应的state上去。在这个过程中我们实际上是可以访问到当前props的,这样我们可能会对this .props做-些奇奇怪怪的
操作,很可能会破坏state数据的单一数据源, 导致组件状态变得不可预测。
而在getDerivedStateFromProps中禁止了组件去访问this.props,强制让开发者吡较nextProps与prevState 中的值,
以确保当开发者用到getDerivedStateFromProps这个生命周期函数时,就是在根据当前的props来更新组件的state,而
不是去访问this props并做其他一些让组件自身状态变得更加不可预测的事情。
那么 componentWillUpdate为什么被改为getSnopshotBeforeUpdate呢??
老版本使用的两个参数是nextProps与nextState进行对比,而componentDidUpdate中是prevProps与prevState;新版本使用prevProps与prevState,与componentDidUpdate中的prevProps与prevState参数相同;
在React开启异步渲染模式后,在执行函数时读到的DOM元素状态并不总是渲染时相同,这就导致在
componentDidUpdate中使用componentWillUpdate中读取到的DOM元素状态是不安全的,因为这时的值很有可能已经
失效了。
而getSnapshotBeforeUpdate会在最终的render之前被调用,也就是说在getSnapshotBeforeUpdate中读取到的DOM
元素状态是可以保证与componentDidUpdate中-致的。