学习react的生命周期的时候认为会vue差不多, 后果发现还是有差异的, vue3的生命周期则和vue2没什么变动,
这次文章比拟长, 比拟偏重父子生命周期程序和react方面, 其中一些图片是援用局部文章的
喜爱就给个赞吧, 该系列还在更新
react
组件生命周期图
生命周期API
Col1 | Col2 |
---|---|
挂载 | |
constructor | 组件挂载之前被调用 |
shouldComponentUpdate(nextProps, nextState) | 在调用 render办法之前调用,在初始化和后续更新都会被调用 |
render | 办法是class组件中惟一必须实现的办法,用于渲染dom, render()办法必须返回reactDOM |
componentDidMount | 组件挂载后 (插入DOM树后) 立刻调用 |
更新 | |
shouldComponentUpdate(nextProps, nextState) | 组件更新之前调用,能够管制组件是否进行更新, 返回true时组件更新, 返回false则不更新 |
getSnapshotBeforeUpdate(prevProps, prevState) | 最近一次的渲染输入被提交之前调用。也就是说,在 render 之后,行将对组件进行挂载时调用。 |
componentDidUpdate(prevProps, prevState, snapshot) | 更新后会被立刻调用。首次渲染不会执行, 第三个是“snapshot” 参数传递 |
卸载 | |
componentWillUnmount | 组件行将被卸载或销毁时进行调用。 |
hooks 模仿生命周期
模仿 componentDidMount
useEffect(() => console.log('componentDidMount'), []);
模仿shouldComponentUpdate
const MemoChild = React.memo( () => {...}, (prevProps, nextProps) => nextProps.count !== prevProps.count)
模仿componentDidUpdate
useEffect(() => console.log('mounted or updated'));
不仅能够拜访 componentDidUpdate,还能够拜访componentDidMount,如果只想模仿 componentDidUpdate,
const ref = useRef(true);useEffect(() => { if (ref.current) { ref.current = false; } console.log('componentDidUpdate')});
模仿componentWillUnmount
useEffect(() => { return () => { console.log('模仿componentWillUnmount'); }}, []);
父子组件生命周期程序
Parent.tsx
为了更好的阐明, Parent.tsx 应用的是hooks写法
const MemoChild = React.memo( () => { useEffect(() => console.log("MemoChild. componentDidMount"), []); console.log("MemoChild, function render"); return <div>memo</div>; }, () => false);function Parent() { let [show, setShow] = useState(true); console.log("Parent, function render"); useEffect(() => console.log("Parent. componentDidMount"), []); useEffect(() => () => console.log("Parent. componentWillUnmount"), []); useEffect(() => console.log("Parent. show updated"), [show]); return ( <ul> <button onClick={() => { setShow(!show); }} > 按钮 </button> {show ? ( <Child count2={2333}> <MemoChild></MemoChild> </Child> ) : ( <MemoChild></MemoChild> )} </ul> );}
Child.tsx
Child.tsx应用的是ReactComponent写法
import React from "react";interface countProp { count2: number;}interface testState { count: number;}class Child extends React.Component<countProp, testState> { static getDerivedStateFromProps(props: countProp, _state: testState) { console.log("Child. getDerivedStateFromProps"); return { count: props.count2, }; } constructor(props: countProp) { super(props); this.state = { count: 0, }; console.log("Child. constructor"); } componentDidMount() { this.setState({ count: this.state.count + 123, }); console.log("Child. componentDidMount"); } shouldComponentUpdate() { console.log("Child. shouldComponentUpdate"); return true; } getSnapshotBeforeUpdate() { console.log("Child. getSnapshotBeforeUpdate"); return null; } componentDidUpdate(props: any, state: any, snapshot: any) { console.log("Child. componentDidUpdate"); console.log("snapshot:", snapshot); } componentWillUnmount() { clearInterval(this.timerID); console.log("Child. componentWillUnmount"); } render() { const { children } = this.props; const { count } = this.state; console.log("Child. render"); return ( <> <ul> <li>state: {count}</li> </ul> {children} </> ); }}
程序
下面渲染到挂载代码打印的程序
Parent, function render Child. constructor Child. getDerivedStateFromProps Child. render MemoChild, function render Child. componentDidMount MemoChild. componentDidMount Parent. componentDidMount Parent. show updated
在Child.tsx中componentDidMount周期中应用到setData, 打印
Child. getDerivedStateFromProps Child. shouldComponentUpdate Child. render Child. getSnapshotBeforeUpdate Child. componentDidUpdate snapshot: null
当咱们点击parent的按钮, 暗藏Child.tsx, 打印
Parent, function renderMemoChild, function renderChild. componentWillUnmountParent. show updated
React总结
组件到挂载期间, 先实现
Parent function > Child(constructor->getDerivedStateFromProps->render) > MemoChild function > componentDidMount (Child->MemoChild->Parent)
通过下面的程序能够发现, React的周期是依照子组件程序挂载后, 才挂载Parent
- ==render== 以及 ==render== 之前的生命周期,则 父组件先执行
- ==render== 以及 ==render==之后的申明周期,则子组件先执行,并且是与父组件交替执行
Vue
生命周期图
生命周期API
beforeCreate -> 应用 setup()
created -> 应用 setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeUnmount -> onBeforeUnmount
unmounted -> onUnmounted
errorCaptured -> onErrorCaptured
renderTracked -> onRenderTracked
renderTriggered -> onRenderTriggered
activated -> onActivated
deactivated -> onDeactivated
onRenderTracked 和 onRenderTriggered
其中新增了两个onRenderTracked 和onRenderTriggered. 提供调试应用
- onRenderTracked(状态跟踪), 当组件第一次渲染时, 咱们设置响应值(a)的时候, 并且get(比方html中的 {{a}})获取时触发
onRenderTriggered(状态触发), 扭转响应值触发
event 对象属性
- newValue 更新后变量的值
- oldValue 更新前变量的值
target 目前页面中的响应变量和函数
生命周期API
Col1 | Col2 |
---|---|
setup | 在实例初始化之后、挂载之前, 无奈获取到dom节点。 |
beforeMount | 在挂载开始之前被调用:相干的render 函数首次被调用 |
mounted | 在实例挂载实现后被调用,这时候传递给 app.mount 的元素曾经被新创建的 vm.$el 替换了 |
beforeUpdate | 在数据产生扭转后,DOM 被更新之前被调用。 |
updated | 在数据更改导致的虚构 DOM 从新渲染和更新结束之后被调用。 |
activated | 被 keep-alive 缓存的组件激活时调用。即页面显示在屏幕上时 |
deactivated | deactivated |
beforeUnmount | 在卸载组件实例之前调用。在这个阶段,实例依然是齐全失常的。 |
unmounted | 卸载组件实例后调用。 |
errorCaptured | 在捕捉一个来自后辈组件的谬误时被调用。 |
renderTracked | 跟踪虚构 DOM 从新渲染时调用。 |
renderTriggered | 当虚构 DOM 从新渲染被触发时调用。 |
父子周期程序
Parent.vue
<template> <div> <button @click="onBtnClick">按钮</button> <!-- <button @click="count++">按钮count</button> --> <Child v-if="bool"> </Child> <div>{{ count }}</div> </div></template><script setup lang="ts">import { onActivated, onDeactivated, onMounted, onRenderTracked, onRenderTriggered, onUnmounted, onUpdated, ref } from "vue";import Child from "./Child.vue";console.log("Parent setup");const bool = ref(true);let count = ref(0);function onBtnClick() { bool.value = !bool.value;}onMounted(() => { console.log("Parent onMounted"); count.value++;});onUpdated(() => { console.log("Parent onUpdated");});onRenderTracked((event) => { console.log("Parent onRenderTracked", event);});onRenderTriggered((event) => { console.log("Parent onRenderTriggered", event);});onActivated(() => { console.log("Parent onActivated");});onDeactivated(() => { console.log("Parent onDeactivated");});onUnmounted(() => { console.log("Parent onUnmounted");});</script>
Child.vue
<template> <div>Child {{ count }}</div></template><script lang="ts">import { ref, defineComponent } from "vue";export default defineComponent({ setup() { const count = ref(0); console.log("Child setup"); return { count }; }, mounted() { console.log("Child onMounted"); this.count++; }, updated() { console.log("Child updated"); }, activated() { console.log("Child onActivated"); }, deactivated() { console.log("Child onDeactivated"); }, renderTracked(event) { console.log("Child onRenderTracked", event); }, renderTriggered(event) { console.log("Child onRenderTriggered", event); }, unmounted() { console.log("Child onUnmounted"); },});</script>
程序
Parent setupParent onRenderTracked {effect: ReactiveEffect, target: RefImpl, type: 'get', key: 'value'}Parent onRenderTracked {effect: ReactiveEffect, target: RefImpl, type: 'get', key: 'value'}Child setupChild onRenderTracked {effect: ReactiveEffect, target: RefImpl, type: 'get', key: 'value'}Child onMountedChild onRenderTriggered {effect: ReactiveEffect, target: RefImpl, type: 'set', key: 'value', newValue: 1}Parent onMountedParent onRenderTriggered {effect: ReactiveEffect, target: RefImpl, type: 'set', key: 'value', newValue: 1}Child onActivatedParent onActivatedParent onUpdatedChild updated
vue生命周期总结
Parent setup > Child setup > Child onMounted > Parent onMounted > Child onActivated > Parent onActivated
onActivated更像$nextTick, 所有子组件挂载后才进行, vue 与 react 类似, 都是挂载前父子程序, 挂载中 则是 子父程序
参考
深刻详解React生命周期
Vue3 官网文档