React的父子组件生命周期
父子组件生命周期:
“生命周期”细想之下有点浪漫主义色彩,不知道是不是从lifecycle英译过来的。作为一个前端从业者,如果让我来取,可能会取成“渲染周期”之类的,毕竟是和浏览器打交道的职业,浏览器的layout使dom树具有骨架,paint则让整个页面光亮起来。
React 的一切都是组件,通过 React.createElement 方法来创建嵌套层级,说白了在内存中构建对象树,据此渲染到浏览器中成为dom树,这个时候一个节点是什么时候真正渲染到页面中就变得重要起来,因为只有这个时候你才能真正和浏览器环境内的对象和方法交互,同样离开的时候也需要清理监听器等防止干扰后续逻辑,因此钩子函数,也可以说是生命周期函数就有了存在的意义。
先上代码:
Document
---CodePen在线演示---
Props 和 State 相关
父组件 App 将自身的State传入了子组件 F 内,忽略挂载和卸载,列举生命周期函数:
1,getDerivedStateFromProps --
通过浏览器打印结果可以看到,不管是组件初始化,还是更新或继承新的 state 或者 props ,最先触发的都是静态钩子函数 getDerivedStateFromProps ;
2,shouldComponentUpdate --
在 setState 异步赋值了 state 的下一个状态后,整个子组件 F 开始收集和对比新旧状态,将新的状态输入到生命周期函数 shouldComponentUpdate 中,写明 return 的值是 truthy 还是 falsy 可以选择中断更新或者继续更新;
3,componentDidUpdate --
在 shouldComponentUpdate 顺利进入下一步后,将执行 render 方法,更新虚拟dom树,浏览器完成渲染,在此之后旧的状态将作为参数传给 componentDidUpdate ,可以对比新状态以及是否保留旧状态;
挂载 和 卸载
componentDidMount 和 componentWillUnmount --
观察父子组件的挂载生命周期函数,可以发现挂载时,子组件的挂载钩子先被触发;卸载时,子组件的卸载钩子后被触发;
对于挂载钩子,一般来说,应该将子组件从上至下依次挂载到一个 fragment 上,再整体挂载到dom树中,因为频繁操作dom树不仅影响性能甚至可能影响用户体验。
但是实际情况却并如此,我们经常在挂载函数上注册监听器,说明此时是可以与页面交互的,也就是说其实所有挂载钩子都是在父组件实际挂载到dom树上才触发的,不过是在父组件挂载后依次触发子组件的 componentDidmount ,最后再触发自身的挂载钩子,说白了,componentDidMount 其实是异步钩子。
相反,卸载的时候父节点先被移除,再从上至下依次触发子组件的卸载钩子;
但是我们也经常在卸载钩子上卸载监听器,这说明 componentWillUnmount 其实在父组件从dom树上卸载前触发的,先触发自身的卸载钩子,但此时并未从dom树上剥离,然后依次尝试触发所有子组件的卸载钩子,最后,父组件从dom树上完成实际卸载。