03 【响应式原理 ref和reactive总结 setup注意点】
1.Vue3.0中的响应式原理
Section titled “1.Vue3.0中的响应式原理”1.1 vue2.x的响应式
Section titled “1.1 vue2.x的响应式”-
实现原理:
-
对象类型:通过
Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。 -
数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
-
-
存在问题:
- 新增属性、删除属性, 界面不会更新。
- 直接通过下标修改数组, 界面不会自动更新。
1.2 Vue3.0的响应式
Section titled “1.2 Vue3.0的响应式”-
实现原理:
-
通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
-
通过Reflect(反射): 对源对象的属性进行操作。
-
MDN文档中描述的Proxy与Reflect:
-
通过Reflect操作的属性,报错时会返回false,这样就不要try-catch捕获异常了。
2.ref和reactive总结
Section titled “2.ref和reactive总结”2.1 reactive对比ref
Section titled “2.1 reactive对比ref”- 从定义数据角度对比:
- ref用来定义:基本类型数据。
- reactive用来定义:对象(或数组)类型数据。
- 备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过
reactive转为代理对象。
- 从原理角度对比:
- ref通过
Object.defineProperty()的get与set来实现响应式(数据劫持)。 - reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
- ref通过
- 从使用角度对比:
- ref定义的数据:操作数据需要
.value,读取数据时模板中直接读取不需要.value。 - reactive定义的数据:操作数据与读取数据:均不需要
.value。
- ref定义的数据:操作数据需要
2.2 ref
Section titled “2.2 ref”1.ref通常用于声明基础类型响应式数据 。
2.ref返回的是被包装过的响应式对象,在setup中访问和修改ref需要使用.value属性
3.在模板中使用时无需使用.value,直接使用即可
4.当ref数据作为props传递给子组件的时候,在子组件里需要使用toRef或者toRefs建立引用,否则数据不是响应式的 。且需要注意,如果在子组件中直接操作了这个引用之后,则和父组件不在具有联系。
2.3 reactive
Section titled “2.3 reactive”1.reactive用于声明复杂类型响应式数据 。
2.reactive返回的是被包装过的响应式对象,在setup中访问和修改直接使用属性即可
3.声明时未定义,动态添加的属性也会是响应式的
4.在模板中使用属性的形式
5.将reactive声明的响应式数据传递给子组件时,在子组件可以直接使用。
1.当ref的值是数组时,我们可以通过索引来修改数组值是响应式的。
2.4 注意事项
Section titled “2.4 注意事项”1.注意当ref用于在模板中作为真值判断时,直接使用ref恒为true, 需要使用.value才能正确显示
2.注意不能解构reactive数据 ,解构出的数据会失去响应式。
3.在任何地方访问响应式数据都能拿到最新的。
4.同vue2的data,只有数据被应用到模板中时,数据的改变才会触发updated生命周期 ,否则即使数据被修改了,也不会触发updated生命周期,导致视图不更新。
5.同vue2,当将ref和reactive作为props传递给组件时,原则上不应该在子组件上修改props的值。
3.setup的两个注意点
Section titled “3.setup的两个注意点”- setup执行的时机
- 在beforeCreate之前执行一次,this是undefined。
- setup的参数
- props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
- context:上下文对象
- attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于
this.$attrs。 如果子组件没有使用props:[‘xxx’]接收,attr这个对象就能看到父组件传来的数据 - slots: 收到的插槽内容, 相当于
this.$slots。 - emit: 分发自定义事件的函数, 相当于
this.$emit。 一定要在配置里写emits:['hello'], 这里要写父组件的自定义函数名称,不然会有警告
- attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于
App.vue
Demo.vue
