>웹 프론트엔드 >View.js >Vue의 반응형 데이터 처리 방법에 대한 심층 분석

Vue의 반응형 데이터 처리 방법에 대한 심층 분석

青灯夜游
青灯夜游앞으로
2023-03-28 19:14:402242검색

이 기사는 Vue를 배우고 Vue가 반응형 데이터를 처리하는 방법에 대해 이야기하는 데 도움이 될 것입니다. 모두에게 도움이 되기를 바랍니다!

Vue의 반응형 데이터 처리 방법에 대한 심층 분석

vue의 반응형 데이터에 대해 많은 의구심을 가지실 수 있습니다.

예를 들어 프록시로 전환해야 하는 이유는 무엇입니까?

예를 들어, 반응성과 참조라는 두 가지 API가 있는 이유는 무엇입니까?

예를 들어 Vue는 응답성을 어떻게 구현합니까?

사실 이에 대한 답은 소스코드에서 찾을 수 있습니다.

첫 번째 글에서 vue3의 업그레이드는 무엇인지, 프록시 사용의 이점과 Object.defineProperty의 단점에 대해서도 언급했습니다. 하지만 오늘은 각도를 바꿔 chatGPT가 이 질문에 답하도록 하고자 합니다. [관련 추천 : vuejs 영상 튜토리얼, 웹 프론트엔드 개발]

글쎄요, 제가 요약한 것보다 더 좋은 것 같아요.

Vue의 반응형 데이터 처리 방법에 대한 심층 분석

그런 다음 다음 질문으로 넘어가세요.

Vue의 반응형 데이터 처리 방법에 대한 심층 분석

이 답변은 좀 더 공식적인 느낌이 들지만 제가 원하는 답변은 아닙니다.

그 이유는 실제로 매우 간단합니다. 왜냐하면 프록시 메소드는 값 유형을 프록시할 수 없고 객체만 프록시할 수 있기 때문입니다. 따라서 값 유형 데이터를 처리하려면 추가적인 방법이 필요합니다.

물론 하나의 참조로 전 세계를 장악할 수도 있습니다. vue 소스 코드가 호환되면 자동으로 변환됩니다.

이런 이해를 바탕으로 vue3 소스 코드를 모방하여 살펴보겠습니다. 반응형 시스템을 구현합니다.

클릭하면 관련 코드를 볼 수 있습니다. 기사 제목에 따라 다른 지점을 선택하면 됩니다.

Reactive 구현

Reactive가 실제로는 프록시 객체라는 것을 이전 글에서 소개하기도 했습니다.

프록시를 사용하여 간단한 프록시 기능을 반응적으로 구현할 수 있습니다.

      function reactive(target) {        const isObject = (val) =>  val !== null && typeof val === 'object'

        if (!isObject(target)) {          console.warn(`数据必须是对象: ${String(target)}`)          return target
        }        const proxy = new Proxy(target, {          get: (target, key, receiver) => {            console.log('get', key)            const res = Reflect.get(target, key, receiver)            // track(target, key)
            // 这句很关键,不然嵌套数据,里面的不会响应
            if (isObject(res)) {              return reactive(res)
            }            return res
          },          set: (target, key, value, receiver) => {            console.log('set', key, value)            const result = Reflect.set(target, key, value, receiver)            // trigger(target, key, value)
            return result
          },          deleteProperty: () => {            const result = Reflect.deleteProperty(target, key)            return result
          }
        })        return proxy
      }      const person = reactive({        name: '',        age: 18,        like: ['apple']
      })

      person.name  = 'vue test'复制代码

참고: Reflect

Reflect.get(target, key)는 target[key]에 직접 액세스하는 것과 약간 다릅니다.

프록시 객체에서 이를 가리키는 get, set 등이 있는 경우 리디렉션될 수 있습니다.

예:

        const person = new Proxy({            name: "vue test",            age: 18,            get info() {                return 'name is :' + this.name + ' age is:' + this.age
            }
        }, {            get: (target, key, receiver) => {                console.log('get', key)                // return target[key]
                return Reflect.get(target, key, receiver)
            }
        })        console.log(person.info)复制代码

Reflect를 사용하면 이름과 나이에 액세스할 때 이를 트리거할 수 있습니다. Vue의 반응형 데이터 처리 방법에 대한 심층 분석

대상으로 변경한 후에는 정보에서 한 번만 실행됩니다.

return target[key]复制代码

Vue의 반응형 데이터 처리 방법에 대한 심층 분석

ref 구현

vue3에서는 ref가 get 및 set을 통해 구현됩니다.

위와 유사하게 함수를 먼저 선언한 다음 get 및 set을 통해 데이터에 액세스합니다.

      function ref(value) {        return new RefImpl(value)
      }      class RefImpl {        constructor(value) {          // 如果值是对象,则用reactive处理
          this._value = isObject(value) ? reactive(value) : value          // 记录一下初始值
          this._rawValue = value
        }        get value() {          // trackRefValue(this)
          return this._value
        }        set value(newVal) {          if (!Object.is(newVal, this._rawValue)) {            // 更新原始数据
            this._rawValue = newVal            // 更新 .value 的值
            this._value = isObject(newVal) ? reactive(newVal) : value            // triggerRefValue(this)
          }
        }
      }复制代码

소스 코드에서는 get/set이 value를 통해 설정되기 때문에 왜 ref를 .value에서 사용해야 하는지 매우 직관적으로 설명합니다.

종속성 수집 및 트리거 추가

데이터 프록시를 완료했지만 데이터가 변경된 후 구성 요소에 양방향 바인딩을 구현하도록 어떻게 알릴 수 있나요?

답은 수집과 트리거링에 의존하는 것입니다. 즉, get이 트리거되면 get을 트리거하는 조건[함수]을 저장합니다. set이 트리거되면 다시 실행하여 조건[함수]을 트리거하면 됩니다. .

코드를 다시 살펴보겠습니다. 트랙 수집 방법과 대상 트리거 방법을 추가하겠습니다. (즉, 위 코드에서 주석 처리된 두 줄의 코드입니다.)

또한 트리거 기능을 관리하려면 효과 기능이 필요합니다.

      let activeEffect = null
      const targetMap = new WeakMap()      // 依赖收集/触发
      function track(target, key) {        let depsMap = targetMap.get(target)        if (!depsMap) {
          targetMap.set(target, (depsMap = new Map()))
        }        let dep = depsMap.get(key)        if (!dep) {
          dep = new Set()
        }
        dep.add(activeEffect)
        depsMap.set(key, dep)
      }      function trigger(target, key, value) {        const depsMap = targetMap.get(target)        if (!depsMap) {          return
        }        const deps = depsMap.get(key)        if (!deps) {          return
        }

        deps.forEach(effectFn => {          if (effectFn.scheduler) {
            effectFn.scheduler()
          } else {            effectFn()
          }
        })
      }      function effect(fn,options = {}) {        const effectFn = () => {          try {
            activeEffect = effectFn            return fn()
          } catch (error) {
            activeEffect = null
          }
        }        if (!options.lazy) {          effectFn()
        }
        effectFn.scheduler = options.scheduler
        return effectFn
      }      const person = reactive({        name: "hello world"
      })      effect(() => {        console.log('effect person', person.name)
      })      setTimeout(() => {
        person.name = 'setTimeout world'
      }, 2000)复制代码

activeEffect는 트리거 조건 함수를 저장하는 데 사용됩니다.

targetMap은 종속성 사전을 저장하는 데 사용됩니다. 형식은 다음과 같습니다

{
    target: {
        key: []
    }
}复制代码

출력 결과는 hello world입니다. 2초 후에 종속성 함수가 다시 실행되고 setTimeout 세계가 출력됩니다

Vue의 반응형 데이터 처리 방법에 대한 심층 분석

요약

데이터의 프록시는 복잡하지 않습니다. 프록시를 기반으로 일부 경계 처리가 추가됩니다. 응답성을 얻으려면 종속성 수집 및 종속성 트리거 구현을 추가해야 합니다.

effect는 매우 중요한 기능입니다. useEffect 및 watch와 같은 많은 API가 이 기능을 기반으로 개발되었습니다. 컴포넌트 업데이트 역시 이펙트 기능에 기반을 두고 있는데, 이에 대해서는 나중에 설명하겠습니다.

효과가 이해되지 않으면 실행 순서를 정리할 수 있습니다.

  • 1. 효과 함수를 호출하고 fn
  • 2. effectFn 함수를 선언하고 실행한 후 함수를 activeEffect
  • 로 저장합니다. fn을 실행하고 person.name
  • 을 읽습니다.
  • 4. 프록시의 get 프록시를 사용합니다.
  • 5. 종속성을 수집하고 activeEffect에 의해 저장된 함수를 전역 맵에 저장합니다.
  • 6 이때 효과 함수가 실행되고 데이터 업데이트를 기다립니다.
  • 7.2s 마지막으로 프록시가 설정한 프록시로 이동
  • 8. 글로벌 맵에 저장된 함수를 실행하고, 이펙트 함수를 다시 실행한 후 다시 1단계로 돌아갑니다

을 클릭하면 됩니다. 관련 코드를 확인하고 Lesson3 브랜치를 선택하세요.

글과 관련된 코드는 vue/examples에서 보실 수 있으며, 모방 vue 구현 버전은 packages/reactivity에서 보실 수 있습니다.

(학습 영상 공유:

vuejs 입문 튜토리얼, 기본 프로그래밍 영상)

위 내용은 Vue의 반응형 데이터 처리 방법에 대한 심층 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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