3.1:什么是响应性
这个术语在今天的各种编程讨论中经常出现,但人们说它的时候究竟是想表达什么意思呢?本质上,响应性是一种可以使我们声明式地处理变化的编程范式。一个经常被拿来当做典型例子的用例即是Excel表格:
这里单元格A2中的值是通过公式=A0+A1来定义的(你可以在A2上点击来查看或编辑该公式),因此最终得到的值为3,正如所料。但如果你试着更改A0或A1,你会注意到A2也随即自动更新了。
而Javascript默认并不是这样的。如果我们用Javascript写类似的逻辑:
当我们更改A0后,A2不会自动更新。
那我们如何在javascript中做到这一点呢?首先,为了能重新运行计算的代码来更新A2,我们需要将其包装为一个函数:
然后,我们需要定义几个术语:
这个update()函数会产生一个副作用,或者就简称为作用(effect),因为它会更改程序里的状态。
A0和A1被视为这个作用的依赖(dependency),因为它们的值被用来执行这个作用。因此这次作用也可以说是一个它依赖订阅者(subscriber)。
我们需要一个魔法函数,能够在A0或A1(这两个依赖)变化时调用update()(产生作用)。
这个whenDepsChange()函数如有下的任务:
1.当一个变量被读取时进行追踪。例如我们执行了表达式A0+A1的计算,则A0+A1都被读取到了。
2.如果一个变量在当前运行的副作用中被读取了,就将该副作用设为此变量的订阅者。例如由于A0+A1在update()执行时被访问到了,则update()需要在第一次调用之后成为A0和A1的订阅者。
3.探测一个变量的变化。例如当我们给A0赋了一个新值之后,应该通知其所有订阅了的副作用重新执行。
3.2选项式API的响应式数据
可用data选项来声明组建的响应式状态;该data选项的值应返回一个对象的函数;
data函数返回对象的所有顶层属性都会被代理到组件实例(即方法和生命周期钩子中的this)上
选项式API的响应式数据:
3.3组合式API的响应式数据
如果在组合式API中直接声明普通变量的数据源,他们并不具备响应式数据
3.2.1:reactive()函数
reactive()函数只对独享类型有效(对象、数组、Map、Set),对string、number和boolean这样的原始类型无效
reactive接收一个普通对象然后返回该普通对象的响应式代理
普通对象==>返回一个proxy对象,响应式转换是深层的,对影响对象内部有嵌套的属性
用user.name="new name"来修改值
内部基于proxy实现
获取数据值的时候直接截取,不需要加.value
参数只能传入对象类型
3.2.2:ref()函数
使用ref()方法我们可以创建任何类型的响应式数据,获取时需要通过.value来进行获取
当值为对象类型时,会用reactive()自动转换它的.value
ref接受一个内部值并返回一个响应式可变的ref对象
任意类型==>返回一个ref对象
用num.value=***来修改值
获取数据值的时候需要加.value。可以理解为ref是通过reactive包装了一层具有value属性的对象来实现的
参数可以传递任意数据类型,传递对象类型时也能保持深度响应式,所以适用性更广,setup中定义数据时推荐优先使用ref,方便逻辑拆分和业务解耦
template中使用ref值不用通过value获取(导出后已默认做了一个解构),js中使用ref必须通过.value获取
ref获取元素
3.2.3:toref()函数
toref用于为源响应式对象上的的属性新建一个ref,从而保持对其源对象属性的响应式连接。接收两个参数:源响应式对象和属性名,返回一个ref数据。例如使用父组件传递的props数据时,要引用props的某个属性且要保持响应式连接时就很有用。
template中直接获取值,js中需要加.value获取数据值
toref的ref数据不是原始数据的拷贝,而是引用,改变结果数据的值也会同时改变原始数据
不会触发UI界面的更新
3.2.4 toRefs()函数
toRefs用于将响应式对象转换为普通对象,但是其中的每个属性都会指向原始对象相应属性的ref(也就是依然保持响应式)。常用于es6的解构赋值操作,因为在对一个响应式对象直接解构时解构后的数据将不再有响应式,而使用torefs可以方便解决这一问题。
获取数据值的时候需要加.value
torefs后的ref数据不再是原始数据的拷贝,而是引用,改变结果数据的值也会同时改变原始数据
作用其实和toref类似,只不过toref是一个个手动赋值,而torefs是是自动赋值。