Vue
父组件和子组件生命周期钩子执行顺序
渲染过程
先创建父组件,然后创建子组件,也就是说父组件的created在子组件created之前。
父组件在子组件之后挂载,故父组件的mounted在子组件mouted之后。

整体渲染过程如下:
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
更新过程
子组件更新过程
- 影响到父组件: 父
beforeUpdate -> 子beforeUpdate -> 子updated -> 父updted
- 不影响父组件: 子
beforeUpdate -> 子updated
父组件更新过程
- 影响到子组件: 父
beforeUpdate -> 子beforeUpdate -> 子updated -> 父updted
- 不影响子组件: 父
beforeUpdate -> 父updated
销毁过程
与渲染类似的:
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
综上,可以看出,Vue父子组件生命周期钩子的执行顺序遵循:从外到内,然后再从内到外的规律。
Vuex
install
Vuex的install通过beforeCreacte钩子中增加处理逻辑,保证了所有组件实例的$store都是同一份Store实例:
1function vuexInit () {
2 const options = this.$options
3 // 注入$store
4 if (options.store) { // 存在store表明为根节点,为根节点设置$store
5 this.$store = typeof options.store === 'function'
6 ? options.store()
7 : options.store
8 } else if (options.parent && options.parent.$store) { // 子节点取父节点的$store
9 this.$store = options.parent.$store
10 }
11}
数据响应化
Vuex通过new Vue()的方式实现state和computed的响应化,具体通过resetStoreVM方法:
1function resetStoreVM (store, state, hot) {
2 /* 存放之前的vm对象 */
3 const oldVm = store._vm
4
5 // 通过Object.defineProperty为每一个getter方法设置get代理方法,将getter的属性代理到store._vm上,通过访问其计算属性的方式实现get
6 store.getters = {}
7 const wrappedGetters = store._wrappedGetters
8 const computed = {}
9
10 forEachValue(wrappedGetters, (fn, key) => {
11 computed[key] = () => fn(store)
12 Object.defineProperty(store.getters, key, {
13 get: () => store._vm[key],
14 enumerable: true // for local getters
15 })
16 })
17
18 // Vue.config.silent暂时设置为true的目的是在new一个Vue实例的过程中不会报出一切警告
19 const silent = Vue.config.silent
20
21 Vue.config.silent = true
22
23 /* 这里new了一个Vue对象,运用Vue内部的响应式实现注册state以及computed*/
24 store._vm = new Vue({
25 data: {
26 $$state: state
27 },
28 computed
29 })
30 Vue.config.silent = silent
31
32 // enable strict mode for new vm
33 /* 使能严格模式,保证修改store只能通过mutation */
34 if (store.strict) {
35 enableStrictMode(store)
36 }
37
38 if (oldVm) {
39 /* 解除旧vm的state的引用,以及销毁旧的Vue对象 */
40 if (hot) {
41 store._withCommit(() => {
42 oldVm._data.$$state = null
43 })
44 }
45 Vue.nextTick(() => oldVm.$destroy())
46 }
47}
严格模式
Vuex严格模式下,所有修改state的操作必须通过mutation实现,否则会抛出错误。这是通过watch state实现的:
1function enableStrictMode (store) {
2 store._vm.$watch(function () { return this._data.$$state }, () => {
3 if (process.env.NODE_ENV !== 'production') {
4 /* 检测store中的_committing的值,如果是true代表不是通过mutation的方法修改的 */
5 assert(store._committing, `Do not mutate vuex store state outside mutation handlers.`)
6 }
7 }, { deep: true, sync: true })
8}
Object.defineProperty有哪些缺点
Object.defineProperty只能劫持对象的属性,而Proxy 是直接代理对象。由于Object.defineProperty 只能对属性进行劫持,需要遍历对象的每个属性。而Proxy 可以直接代理对象。
Object.defineProperty对新增属性需要手动进行 Observe。由于Object.defineProperty 劫持的是对象的属性,所以新增属性时,需要重新遍历对象,对其新增属性再使用Object.defineProperty进行劫持。 也正是因为这个原因,使用Vue给data 中的数组或对象新增属性时,需要使用vm.$set 才能保证新增的属性也是响应式的。
Proxy支持13种拦截操作,这是defineProperty所不具有的。
Proxy作为新标准,长远来看,JS引擎会继续优化Proxy ,但getter和setter基本不会再有针对性优化。
Proxy兼容性差目,前并没有一个完整支持Proxy所有拦截方法的Polyfill方案
Vue3新特性
- 基于
Proxy实现数据变动的监听
- 使用
TypeScript开发
- 组合式
API(Composition API)
Composition API
是较低级别的数据驱动视图和组件生命周期API,能够实现一种更自由形式的编写组件逻辑的方式。可以像编写函数一样自由地表达,编写和重用有状态组件逻辑
Composition API完全可以和现有的Options API配合使用
Composition API会在Options API之前解析,并且不能提前访问这些选项中定义的 property
setup()函数返回的property将会被暴露给 this,在 Options API中可以访问到
Ref
Ref是为了以变量形式传递响应式的值而引入的“新”概念。基本类型值需要以Ref的形式引用
1import { ref, onMounted, onUnmounted } from 'vue'
2
3export function useMousePosition() {
4 const x = ref(0)
5 const y = ref(0)
6
7 function update(e) {
8 x.value = e.pageX
9 y.value = e.pageY
10 }
11
12 onMounted(() => {
13 window.addEventListener('mousemove', update)
14 })
15
16 onUnmounted(() => {
17 window.removeEventListener('mousemove', update)
18 })
19
20 return { x, y }
21}
Reactive的应用类型解构赋值时候,会失去可响应性,需要用toRefsAPI
1function useMousePosition() {
2 const pos = reactive({
3 x: 0,
4 y: 0,
5 })
6
7 // ...
8 return toRefs(pos)
9}
与React Hooks相比
基于函数的Composition API提供了与React Hooks 同等级别的逻辑组合能力。但其setup()函数只会被调用一次,因此有一下优点:
- 一般来说更符合惯用的
JavaScript代码的直觉
- 不需要顾虑调用顺序,可以用在条件语句中
- 不会在每次渲染时重复执行,可以以降低垃圾回收的压力
- 不存在内联处理函数导致子组件永远更新的问题,不需要
useCallback
- 不存在忘记记录依赖的问题,也不需要
useEffect和useMemo并传入依赖数组以捕获过时的变量。Vue的自动依赖跟踪可以确保侦听器和计算值总是准确无误