>웹 프론트엔드 >View.js >Vue3의 반응 메커니즘은 무엇입니까?

Vue3의 반응 메커니즘은 무엇입니까?

PHPz
PHPz앞으로
2023-05-12 17:07:061096검색

응답성이란 무엇입니까

응답성은 항상 Vue의 특별한 기능 중 하나였습니다. 반면에 JavaScript의 변수에는 응답성이라는 개념이 없습니다. 이는 JavaScript를 배울 때 처음으로 배우는 개념입니다. 즉, 코드는 위에서 아래로 실행됩니다.

다음 코드를 살펴보겠습니다. 코드가 실행된 후, 코드에서 count 값을 수정한 후에도 두 개의 double 결과가 출력됩니다. 값에는 변화가 없습니다

let count = 1
let double = count * 2
count = 2

double의 값은 count의 값에 2를 곱한 값을 기준으로 계산됩니다. 이제 count의 변화에 ​​따라 double이 변경되도록 하려면 count의 값을 변경해야 합니다. 매번 수정 후 double을 다시 계산합니다

예를 들어 다음 코드에서는 먼저 double을 계산하는 논리를 함수로 캡슐화한 다음 개수를 수정한 후 다시 실행하면 최신 double 값을 얻게 됩니다

let count = 1
// 计算过程封装成函数
let getDouble = n=>n*2 //箭头函数
let double = getDouble(count)
count = 2
// 重新计算double ,这里我们不能自动执行对double的计算
double = getDouble(count)

실제 개발의 계산 로직은 double을 계산하는 것보다 훨씬 복잡하지만 실행을 위해 함수로 캡슐화할 수 있습니다. 다음으로 고려해야 할 것은 double의 값을 자동으로 계산하는 방법입니다

만약 가능하다면; getDouble 함수가 자동으로 실행되도록 합니다. 즉, 아래 그림과 같이 JavaScript의 특정 메커니즘을 사용하여 개수가 수정될 때마다 double 값이 동기적으로 업데이트됩니다. 카운트의 변화에 ​​따라 자동으로 변하는 double이 바로 반응성의 원형인 것 같아요

Vue3의 반응 메커니즘은 무엇입니까?


반응성의 원리

반응성의 원리는 무엇인가요? Vue에는 defineProperty, Proxy 및 value setter라는 세 가지 반응형 솔루션이 있습니다. 먼저 Vue 2의 defineProperty API를 살펴보겠습니다.

다음 코드에서는 obj 객체를 정의하고, defineProperty를 사용하여 프록시를 사용합니다. 이런 방식으로 obj 객체의 value 속성을 가로채고, count 속성을 읽을 때 get 함수를 실행하고, count 속성을 수정할 때 set 함수를 실행하고, set 함수 내에서 double을 다시 계산합니다. 이런 식으로 우리는 간단한 반응형 기능을 구현했습니다. 과정의 네 번째 부분에서는 더욱 완전한 반응형 시스템을 작성하도록 안내하겠습니다

하지만 DefineProperty API는 Vue 2처럼 반응성의 원칙을 구현합니다. 예를 들어 다음 코드에서 obj.count 속성을 삭제하면 set 함수가 실행되지 않고 double은 여전히 ​​이전 값이 됩니다. 이것이 Vue 2에서 필요한 이유입니다. 데이터를 삭제하는 특수 기능

let getDouble = n=>n*2
let obj = {}
let count = 1
let double = getDouble(count)
Object.defineProperty(obj,'count',{
    get(){
        return count
    },
    set(val){
        count = val
        double = getDouble(val)
    }
})
console.log(double) // 打印2
obj.count = 2
console.log(double) // 打印4 有种自动变化的感觉

Vue 3의 반응 메커니즘은 Proxy를 기반으로 구현되었습니다. Proxy라는 이름에서 프록시를 의미한다는 것도 알 수 있습니다. Proxy의 중요한 의미는 Vue 2의 응답성의 단점을 해결한다는 것입니다$delete

우리는 아래 코드를 보세요. 새 프록시를 통해 객체 obj를 프록시한 다음 get, set 및 deleteProperty 함수를 통해 객체의 읽기, 수정 및 삭제 작업을 프록시하여 응답 기능을 실현합니다.

delete obj.count
console.log(double) // doube还是4

우리는 다음에서 시작합니다. 여기에서 Proxy에 의해 구현된 함수는 Vue 2의 DefinePropery와 유사하다는 것을 알 수 있습니다. 사용자가 데이터를 수정할 때 set 함수를 트리거하여 double을 자동으로 업데이트하는 기능을 실현할 수 있습니다. 또한 Proxy는 DefinePropery의 여러 가지 결함을 개선했습니다. 예를 들어 특정 속성이 아닌 개체의 삭제를 모니터링할 수 있으므로 정의할 때 존재하지 않는 프록시 속성뿐만 아니라 더 풍부한 프록시도 사용할 수 있습니다. Map, Set 등과 같은 데이터 구조를 구현하고 deleteProperty를 통해 삭제 작업 프록시를 구현할 수도 있습니다

물론 Proxy에 대한 이해를 돕기 위해 set 및 deleteProperty 함수에 이중 관련 코드를 작성할 수도 있습니다. 과정의 후반부에서는 보다 완전한 캡슐화를 수행하도록 안내하겠습니다. 예를 들어 다음 코드에서 Vue 3의 반응성 기능은 객체를 반응형 데이터로 변환할 수 있으며 반응성은 프록시를 기반으로 구현됩니다. obj.count를 수정한 후 watchEffect를 사용하여 데이터를 인쇄할 수도 있습니다.

let proxy = new Proxy(obj,{
    get : function (target,prop) {
        return target[prop]
    },
    set : function (target,prop,value) {
        target[prop] = value;
        if(prop==='count'){
            double = getDouble(value)
    }
},
deleteProperty(target,prop){
    delete target[prop]
    if(prop==='count'){
        double = NaN
    }
   }
})
console.log(obj.count,double)
proxy.count = 2
console.log(obj.count,double)
delete proxy.count
// 删除属性后,我们打印log时,输出的结果就会是 undefined NaN
console.log(obj.count,double)

프록시를 사용하면 응답 메커니즘이 더 완벽하지만 Vue 3에는 객체를 사용하는 또 다른 응답 구현 로직이 있습니다. get 및 set 함수는 모니터링에 사용됩니다. . 이 반응형 구현은 특정 속성의 수정만 가로챌 수 있습니다. 이는 Vue 3의 ref API 구현이기도 합니다.

다음 코드에서는 count 속성의 값을 가로채고 설정 작업을 가로채는 것도 가능합니다. 유사한 기능

import {reactive,computed,watchEffect} from 'vue'
let obj = reactive({
    count:1
})
let double = computed(()=>obj.count*2)
obj.count = 2
watchEffect(()=>{
    console.log('数据被修改了',obj.count,double.value)
})

세 가지 유형의 응답성의 차이점을 이해하는 데 도움이 되도록 세 가지 구현 원칙의 비교표는 다음과 같습니다

实现原理 defineProperty Proxy value setter
实际场景 Vue 2 响应式 Vue 3 reactive Vue 3 ref
优势 兼容性 基于proxy实现真正的拦截 实现简单
劣势 数组和属性删除等拦截不了 兼容不了 IE11 只拦截了 value 属性
实际应用 Vue 2 Vue 3 复杂数据结构 Vue 3 简单数据结构

定制响应式数据

简单入门响应式的原理后,接下来我们学习一下响应式数据在使用的时候的进阶方式;我们看下使用 <script setup></script> 重构之后的 todolist 的代码;这段代码使用 watchEffect,数据变化之后会把数据同步到 localStorage 之上,这样我们就实现了 todolist 和本地存储的同步

import { ref, watchEffect, computed } from "vue";
let title = ref("");
let todos = ref(JSON.parse(localStorage.getItem(&#39;todos&#39;)||&#39;[]&#39;));
watchEffect(()=>{
    localStorage.setItem(&#39;todos&#39;,JSON.stringify(todos.value))
})
function addTodo() {
    todos.value.push({
        title: title.value,
        done: false,
    });
    title.value = "";
}

更进一步,我们可以直接抽离一个 useStorage 函数,在响应式的基础之上,把任意数据响应式的变化同步到本地存储;我们先看下面的这段代码,ref 从本地存储中获取数据,封装成响应式并且返回,watchEffect 中做本地存储的同步,useStorage 这个函数可以抽离成一个文件,放在工具函数文件夹中

function useStorage(name, value=[]){
    let data = ref(JSON.parse(localStorage.getItem(name)||&#39;[]&#39;))
    watchEffect(()=>{
        localStorage.setItem(name,JSON.stringify(data.value))
    })
    return data
}

在项目中我们使用下面代码的写法,把 ref 变成 useStorage,这也是 Composition API 最大的优点,也就是可以任意拆分出独立的功能

let todos = useStorage(&#39;todos&#39;,[])
function addTodo() {
    ...code
}

现在,你应该已经学会了在 Vue 内部进阶地使用响应式机制,去封装独立的函数;在后续的实战应用中,我们也会经常对通用功能进行封装;如下图所示,我们可以把日常开发中用到的数据,无论是浏览器的本地存储,还是网络数据,都封装成响应式数据,统一使用响应式数据开发的模式;这样,我们开发项目的时候,只需要修改对应的数据就可以了

Vue3의 반응 메커니즘은 무엇입니까?

基于响应式的开发模式,我们还可以按照类似的原理,把我们需要修改的数据,都变成响应式;比如,我们可以在 loading 状态下,去修改浏览器的小图标 favicon;和本地存储类似,修改 favicon 时,我们需要找到 head 中有 icon 属性的标签

在下面的代码中,我们把对图标的对应修改的操作封装成了 useFavicon 函数,并且通过 ref 和 watch 的包裹,我们还把小图标变成了响应式数据

import {ref,watch} from &#39;vue&#39;
export default function useFavicon( newIcon ) {
    const favicon = ref(newIcon)
    const updateIcon = (icon) => {
        document.head
        .querySelectorAll(`link[rel*="icon"]`)
        .forEach(el => el.href = `${icon}`)
    }
watch( favicon,
    (i) => {
        updateIcon(i)
    }
)
    return {favicon,reset}
}

这样在组件中,我们就可以通过响应式的方式去修改和使用小图标,通过对 faivcon.value 的修改就可以随时更换网站小图标;下面的代码,就实现了在点击按钮之后,修改了网页的图标为 geek.png 的操作

<script setup>
    import useFavicon from &#39;./utils/favicon&#39;
    let {favicon} = useFavicon()
    function loading(){
        favicon.value = &#39;/geek.png&#39;
    }
</script>
<template>
    <button @click="loading">123</button>
</template>

Vueuse 工具包

我们自己封装的 useStorage,算是把 localStorage 简单地变成了响应式对象,实现数据的更新和localStorage 的同步;同理,我们还可以封装更多的类似 useStorage 函数的其他 use 类型的函数,把实际开发中你用到的任何数据或者浏览器属性,都封装成响应式数据,这样就可以极大地提高我们的开发效率

Vue 社区中其实已经有一个类似的工具集合,也就是 VueUse,它把开发中常见的属性都封装成为响应式函数

VueUse 趁着这一波 Vue 3 的更新,跟上了响应式 API 的潮流;VueUse 的官方的介绍说这是一个 Composition API 的工具集合,适用于 Vue 2.x 或者 Vue 3.x,用起来和 React Hooks 还挺像的

在项目目录下打开命令行里,我们输入如下命令,来进行 VueUse 插件的安装:

npm install @vueuse/core

然后,我们就先来使用一下 VueUse;在下面这段代码中,我们使用 useFullscreen 来返回全屏的状态和切换全屏的函数;这样,我们就不需要考虑浏览器全屏的 API,而是直接使用 VueUse 响应式数据和函数就可以很轻松地在项目中实现全屏功能

<template>
    <h2 @click="toggle">click</h2>
</template>
<script setup>
import { useFullscreen } from &#39;@vueuse/core&#39;
const { isFullscreen, enter, exit, toggle } = useFullscreen()
</script>

useFullscreen 的封装逻辑和 useStorage 类似,都是屏蔽了浏览器的操作,把所有我们需要用到的状态和数据都用响应式的方式统一管理,VueUse 中包含了很多我们常用的工具函数,我们可以把网络状态、异步请求的数据、动画和事件等功能,都看成是响应式的数据去管理。

위 내용은 Vue3의 반응 메커니즘은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제