首页IT科技vue实现响应式(vue3响应式)

vue实现响应式(vue3响应式)

时间2025-04-30 12:07:33分类IT科技浏览4192
导读:vue3响应式 vue3实现响应式的方法有两种:...

vue3响应式

vue3实现响应式的方法有两种:

第一种运用组合式API中的reactive直接构建响应式             ,组合式API的出现让我们可以直接用setup函数来处理之前的大部分逻辑                   ,同时也避免了this的使用       ,像data             ,watch                   ,computed       ,生命周期函数都声明在setup函数中      ,这样就像react-hooks一样提升代码的复用率                   ,逻辑性更强             。

第二种就是使用传统的 data(){ return{} } 的形式             ,vue3并没有放弃对vue2写法的支持      ,而是对vue2的写法完全兼容                   。

响应式基础API

首先                   ,让我们来看看vue3为响应式提供的一些基础API.

reactive

reactive用于将数据变成响应式数据       。调用reactive后返回的对象是响应式副本而非原始对象             。其原理就是将传入的数据包装成一个Proxy对象                   。

import { reactive, watchEffect } from vue; const data = { count: 0 }; const obj = reactive(data); data === obj // false watchEffect(() => { // 用于响应性追踪 console.log(obj.count); }); setTimeout(() => { obj.count++; }, 2000);

响应式转换是“深层             ”的——它影响所有嵌套 property       。在基于 ES2015 Proxy 的实现中             ,返回的 proxy 是不等于原始对象的      。建议只使用响应式 proxy,避免依赖原始对象                   。

reactive用于复杂数据类型                   ,比如对象和数组等                   ,当传入基础数据类型时,默认情况下修改数据,界面不会自动更新,如果想更新,可以通过重新赋值的方式             。

readonly

接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理      。只读代理是深层的:任何被访问的嵌套 property 也是只读的             ,不能改变值                   ,否则是报错                   。

import { reactive, watchEffect, readonly } from vue; const data = { count: 0 }; const obj = reactive(data); const copy = readonly(obj); watchEffect(() => { // 用于响应性追踪 console.log(obj.count) }); setTimeout(() => { obj.count++; copy.count++; }, 2000);

isProxy

检查对象是否是由 reactive 或 readonly 创建的 proxy             。

import { reactive, readonly, isProxy } from vue; const data = { count: 0 }; const obj = reactive(data); const copy = readonly(obj); console.log(isProxy(obj)); // true console.log(isProxy(copy)); // true console.log(isProxy(data)); // false

isReactive

检查对象是否是由 reactive 创建的响应式代理。如果该代理是 readonly 创建的       ,但包裹了由 reactive 创建的另一个代理             ,它也会返回 true                   。

import { reactive, readonly, isReactive } from vue; const data = { count: 0 }; const obj = reactive(data); const copy = readonly(obj); const immute = readonly(data); console.log(isReactive(obj)); // true console.log(isReactive(copy)); // true console.log(isReactive(data)); // false console.log(isReactive(immute)) // false

isReadonly

检查对象是否是由 readonly 创建的只读代理                   。

import { reactive, readonly, isReadonly } from vue; const data = { count: 0 }; const obj = reactive(data); const copy = readonly(obj); const immute = readonly(data); console.log(isReadonly(obj)); // false console.log(isReadonly(copy)); // true console.log(isReadonly(data)); // false console.log(isReadonly(immute)) // true

toRaw

返回 reactive 或 readonly 代理的原始对象。这是一个“逃生舱                   ”                   ,可用于临时读取数据而无需承担代理访问/跟踪的开销       ,也可用于写入数据而避免触发更改             。不建议保留对原始对象的持久引用                   。请谨慎使用       。

import { reactive, readonly, toRaw } from vue; const data = { count: 0 }; const obj = reactive(data); const immute = readonly(data); console.log(toRaw(obj) === data); // true console.log(toRaw(immute) === data); // true

markRaw

标记一个对象      ,使其永远不会转换为 proxy             。返回对象本身                   。

import { reactive, readonly, isReactive, markRaw } from vue; const data = markRaw({ count: 0 }); const obj = reactive(data); const immute = readonly(data); console.log(isReactive(obj)); // false console.log(obj === data); // true console.log(immute === data); // true // 即使嵌套在其他响应式队中也是非响应式的 const wrap = reactive({data}); console.log(isReactive(wrap.data)); // false

但是如果对标记对象内的属性进行响应化                   ,是可以的       。

const count = reactive({ // data被标记             ,data.count未被标记 count: data.count }) console.log(isReactive(count));

shallowReactive

创建一个响应式代理      ,它跟踪其自身 property 的响应性                   ,但不执行嵌套对象的深层响应式转换      。

import { shallowReactive, isReactive, watchEffect } from vue; const data = { count: 0, nested: { count: 0 } }; const obj = shallowReactive(data); watchEffect(() => { // 追踪obj.count的变化 console.log(obj.count); }); watchEffect(() => { // 追踪obj.nested.count的变化 console.log(obj.nested.count); }); obj.count++; obj.nested.count++; console.log(data.count); // 0 console.log(data.nested.count); // 1 console.log(isReactive(obj.nested)); // false

shallowReadonly

创建一个 proxy             ,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换                   。

import { shallowReadonly, isReadonly } from vue; const data = { count: 0, nested: { count: 0 } }; const obj = shallowReadonly(data); // 报错 obj.count++; obj.nested.count++; console.log(isReadonly(obj.nested)); // false

ref

接受一个内部值并返回一个响应式且可变的 ref 对象             。ref 对象仅有一个 .value值                   ,指向该内部值      。跟reactive类似                   ,也是将数据变成响应式                   。

import { ref, watchEffect } from vue; const count = ref(0); const obj = ref({ count: 0 }) console.log(obj) watchEffect(() => { console.log(count.value); }) watchEffect(() => { console.log(obj.value.count: , obj.value.count); }) count.value++; obj.value.count++;

ref和reactive的区别

ref是把值类型添加一层包装,使其变成响应式的引用类型的值             。ref(0) --> reactive( { value:0 }) reactive 则是引用类型的值变成响应式的值。

两者的区别只是在于是否需要添加一层引用包装             ,对于对象而言                   ,添加一层包装后会被reactive处理为深层的响应式对象       ,在调用unref后就能看到其实对象是一个Reactive对象                   。

像上面的例子             ,使用ref同样可以将对象响应化                   ,不过访问的时候需要调用value.去访问内部属性                   。所以对于对象而言       ,最好使用reative去响应化处理。

unref

如果参数是一个 ref      ,则返回内部值                   ,否则返回参数本身             。这是 val = isRef(val) ? val.value : val 的语法糖函数                   。

import { ref, unref } from vue; const count = ref(0); const obj = ref({ count: 0 }) console.log(unref(count)); // 0 console.log(unref(obj)) // Reactive对象

toRef

可以用来为源响应式对象上的某个属性新创建一个 ref       。然后             ,ref 可以被传递      ,它会保持对其源属性的响应式连接             。

import { reactive, toRef } from vue; const obj = reactive({ count: 0 }) const countRef = toRef(obj, count); countRef.value++; console.log(obj.count) // 1 obj.count++; console.log(countRef) // 2

toRefs

将响应式对象转换为普通对象                   ,其中结果对象的每个属性都是指向原始对象相应属性的 ref                   。

import { reactive, toRefs } from vue; const obj = reactive({ count: 0 }) const countRef = toRefs(obj); countRef.value++; console.log(obj.count) // 1 obj.count++; console.log(countRef.count.value) // 2

toRefs 只会为源对象中包含的属性生成 ref       。如果要为特定的属性创建 ref             ,则应当使用 toRef      。

isRef

检查值是否为一个 ref 对象                   。

import { isRef, ref } from vue; const count = ref(0); console.log(isRef(count)); // true

customRef

创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制             。它需要一个工厂函数                   ,该函数接收 track 和 trigger 函数作为参数                   ,并且应该返回一个带有 get 和 set 的对象      。

使用自定义 ref 通过 v-model 实现 debounce 的示例:

<input v-model="text" /> function useDebouncedRef(value, delay = 200) { let timeout return customRef((track, trigger) => { return { get() { track() return value }, set(newValue) { clearTimeout(timeout) timeout = setTimeout(() => { value = newValue trigger() }, delay) } } }) } export default { setup() { return { text: useDebouncedRef(hello) } } }

shallowRef

创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的                   。

const obj = shallowRef({}) // 改变 ref 的值是响应式的 obj.value = {} // 但是这个值不会被转换             。 isReactive(obj.value) // false

triggerRef

手动执行与 shallowRef 关联的任何作用。

const shallow = shallowRef({ greet: Hello, world }) // 第一次运行时记录一次 "Hello, world" watchEffect(() => { console.log(shallow.value.greet) }) // 这不会触发作用 (effect)             ,因为 ref 是浅层的 shallow.value.greet = Hello, universe // 触发副作用 "Hello, universe" triggerRef(shallow)

computed

接受一个 getter 函数                   ,并根据 getter 的返回值返回一个不可变的响应式 ref 对象                   。

const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // 错误

或者       ,接受一个具有 get 和 set 函数的对象             ,用来创建可写的 ref 对象                   。

const count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: val => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0

watch

vue3中组合式api watch 与vue2中选项式的watch完全等效。watch 需要监听特定的数据源                   ,并在单独的回调函数中执行副作用             。默认情况下       ,它也是惰性的——即回调仅在监听源发生变化时被调用                   。

与 watchEffect 相比      ,watch 允许我们:

惰性地执行副作用; 更具体地说明应触发监听器重新运行的状态; 访问被监听状态的先前值和当前值       。 监听单一源

源数据可以是一个reactive                   ,也可以直接是一个 ref

语法 watch( name , callback, options ) ; name: 需要监听的属性或者返回值的getter函数 callback: 属性改变后执行的方法             ,接受两个参数 newVal: 新值 oldVal: 旧值 options: 配置项      ,可配置如下 deep: Boolean, 是否深度监听 immediate: Boolean                   ,是否立即执行 // 侦听reactive const state = reactive({ count: 0, value: 1 }) // 只监听对象中的count watch( // 使用getter函数保证只监听了state中的count () => state.count, (count, prevCount) => { /* ... */ } ) // 侦听state中所有属性 watch(state, (newVal, oldVal) => { // ... }) // 直接侦听一个 ref const count = ref(0) watch(count, (count, prevCount) => { /* ... */ }) 监听多个源

使用数组来同时侦听多个源数据             ,当任一源数据发生改变都会触发watch

const state = reactive({ count: 0, value: 1 }); const count = ref(0) watch([state, count], ([newState, newCount], [oldState, oldCount]) => { console.log(newState); console.log(newCount); }) state.count++; count.value++; 深度监听

在watch的第三个参数中传入deep: true

const state = reactive({ count: 0, value: { status: false } }); watch(() => state, (newVal, oldVal) => { console.log(不会触发) }) watch(() => state, (newVal, oldVal) => { console.log(触发深度监听) }, { deep: true }) state.value.status = true;

由于getter方法只返回state,对没有对内部的对象进行监听                   ,因此内部对象的属性发生改变不会触发watch             。

当没有使用getter方法而是传入state这个reactive数据                   ,则不需要设置deep: true都会进行深度监听                   。

立即执行

在watch的第三个参数中传入immediate: true,当传入数据就会执行一次       。

watchEffect

立即执行传入的一个函数             ,响应式追踪其依赖                   ,在其依赖变更时重新运行该函数      。

它会监听引用数据类型的所有属性       ,不需要具体到某个属性             ,一旦运行就会立即监听                   ,组件卸载的时候会停止监听

const count = ref(0) watchEffect(() => console.log(count.value)) // -> logs 0 setTimeout(() => { count.value++ // -> logs 1 }, 100) 停止监听

当 watchEffect 在组件的 setup() 函数或生命周期钩子被调用时       ,侦听器会被链接到该组件的生命周期      ,并在组件卸载时自动停止                   。

在一些情况下                   ,也可以显式调用返回值以停止侦听

const stop = watchEffect(() => { /* ... */ }) // later stop() 清除副作用

有时副作用函数会执行一些异步的副作用             ,这些响应需要在其失效时清除 (即完成之前状态已改变了)              。所以侦听副作用传入的函数可以接收一个 onInvalidate 函数作入参      ,用来注册清理失效时的回调      。当以下情况发生时                   ,这个失效回调会被触发:

副作用即将重新执行时 侦听器被停止 (如果在 setup() 或生命周期钩子函数中使用了 watchEffect             ,则在组件卸载时) watchEffect(onInvalidate => { const token = performAsyncOperation(id.value) onInvalidate(() => { // id has changed or watcher is stopped. // invalidate previously pending async operation token.cancel() }) })

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
图像生成器在线(ChatGPT使用案例之图像生成) 网创是啥东西(网创是什么项目-网创坚持才是常态(网创项目合集 持续更新))