响应性原理
响应性本质是监听数据变化,并做出相应的处理
setup
setup函数就是生命周期函数,它替代了beforeCreate和created函数,在setup中可以访问这两个生命周期函数之外的所有生命周期函数,访问生命周期函数时需要在函数名前加上"on"
副作用函数
副作用函数的执行会影响到函数作用域之外的其他内容,如果能够构建一类数据,当数据发生改变时,可以影响到所有依赖他函数的执行,就实现了数据的响应。
也就是说,当一个数据发生变化时,其对应的副作用函数可以重新执行,那么这个数据就是响应式数据
Proxy
代理,创建一个中间层(代理对象),他在对象与外界之间设置了拦截,拦截的是读写数据对象的操作:
- 当数据被访问时,会触发getter方法中的收集依赖,即在数据对象与副作用函数之间建立依赖关系
- 当修改数据时,会触发setter方法中的派发更新,即逐个执行与该数据对象由依赖关系的副作用函数
响应式数据
响应式数据就是通过副作用函数和Proxy实现的,
- 当VUE项目初始化时,会遍历每个属性,使用Proxy对其进行封装(数据劫持)
- 当使用一个响应式数据的时候,VUE会记录当前依赖,在依赖图中建立对应的记录(依赖追踪)
- 当响应式数据发生变化时,VUE会依次执行依赖图中的函数
响应式API
reactive和ref
- reactive函数根据传入的对象,返回一个深度响应式对象。深度就是无论层级嵌套多深,都会触发数据响应。reactive函数就是根据Proxy来实现响应式的,通过对传入的对象进行包裹,并创建其Proxy对象。
- ref函数只接收一个基本数据类型,并返回一个响应式且可变的数据对象,这个数据对象是一个具有value属性的对象
对响应式对象直接赋新值,会使响应式对象失去响应性:
import { reactive } from 'vue';
const state = reactive({
user: {
name: 'Alice',
details: {
age: 30,
address: '123 Main St'
}
}
});
// 假设我们对state.user.details进行赋新值操作
state.user.details = { age: 31, address: '456 Elm St' };
// 这个新对象{ age: 31, address: '456 Elm St' }不是响应式的
// 因此,对它的修改不会触发视图更新
在上面的例子中,我们对state.user.details
进行了赋新值操作,这个新对象{ age: 31, address: '456 Elm St' }
不是响应式的。如果你希望新对象也是响应式的,你应该使用reactive
来确保新对象的响应性:
state.user.details = reactive({ age: 31, address: '456 Elm St' });
这样,新的对象details
将保持响应性,任何对它的修改都会正确地触发视图更新
toRef和toRefs
这个两者前都可以将响应时对象的属性也转换成响应式的,区别是前者一次只能转换一个属性,后者式可以将所有属性都转换为响应式的
toRef(props,‘name’)
const name_props = toRef(props,‘name’)
console.log(name_props.value)
toRefs(props)
const update_props = toRef(props)
console.log(update_props.name.value)
computed
computed依赖于响应式原始数据,当数据变化时会触发自动触发computed函数,得到一个全新的数据
computed仅接受一个回调函数作为参数,返回一个ref对象
watch
watch函数用于监听指定数据,并在回调函数中调用副作用函数,该函数接受一个被监听对象和回调函数,回调函数包括被监听对象的原始值和更新后的值
const count = Vue.ref(1);
Vue.watch(count,(newVal,oldVal)=>{
console.log(oldVal)
console.log(newVal)
})
provide和inject
当需要在多个层级的组件之间共享数据和函数时,他们允许跨组件定义依赖关系,不需要通过每个层级的props传递数据
privide函数可以提供数据和函数,为后代组件使用
inject用于给后代组件注入provide所提供的数据和函数
当然,因为VUE的单项数据流原则,当父组件的数据发生变化时子组件数据会自动更新,但子组件不能直接修改父组件传递过来的值
若有错误与不足请指出,关注DPT一起进步吧!!!