国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

vue3源碼(二)reactive&effect

這篇具有很好參考價(jià)值的文章主要介紹了vue3源碼(二)reactive&effect。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一.reactive與effect功能

reactive方法會(huì)將對(duì)象變成proxy對(duì)象, effect中使用reactive對(duì)象時(shí)會(huì)進(jìn)行依賴(lài)收集,稍后屬性變化時(shí)會(huì)重新執(zhí)行effect函數(shù)。

<div id="app"></div>
    <script type="module">
      import {
     	reactive,
        effect,
       } from "/node_modules/@vue/reactivity/dist/reactivity.esm-browser.js";
    //   reactive創(chuàng)建一個(gè)響應(yīng)式對(duì)象
    //   effect 副作用函數(shù),默認(rèn)執(zhí)行一次,數(shù)據(jù)變化后再次執(zhí)行
      const state = reactive({ name: "orange", age: 18 });
       effect(() => {
        document.getElementById("app").innerHTML = state.name;
      });
      console.log(state);
      setTimeout(() => {
        state.name = "apple";
      }, 2000);
    </script>

二.reactive與effect實(shí)現(xiàn)

1.實(shí)現(xiàn)reactive

1.1 get、set基礎(chǔ)實(shí)現(xiàn)

// reactive.ts
import { isObject } from "@vue/shared";

const mutableHandlers = {
  get(target, key, receiver) {
    return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
    return Reflect.set(target, key, value, receiver);
  },
};

export function reactive(target) {
  if (!isObject(target)) {
    return target;
  }
  const proxy = new Proxy(target, mutableHandlers);
  return proxy;
}

如下圖,如果采用target[key]方法,獲取aliasName時(shí) 不會(huì)觸發(fā)nameget
vue3源碼(二)reactive&effect,手寫(xiě)vue源碼,vue.js,javascript,前端

1.2 完善重復(fù)

const state = { name: "orange", age: 18 };
      const p1 = reactive(state);
      const p2 = reactive(state);
      const p3 = reactive(p1);
      console.log(p1 === p2);
      console.log(p1 === p3);
  • 響應(yīng)式數(shù)據(jù)緩存,防止重復(fù)代理
    使用map,key為對(duì)象,值為響應(yīng)式對(duì)象,實(shí)現(xiàn)p1 === p2
const reactiveMap = new WeakMap(); //內(nèi)存泄漏
export function reactive(target) {
  if (!isObject(target)) {
    return target;
  }
  const exitProxy = reactiveMap.get(target);
  if (exitProxy) {
    return exitProxy;
  }
  const proxy = new Proxy(target, mutableHandlers);
  reactiveMap.set(target, proxy);
  return proxy;
}
  • 響應(yīng)式數(shù)據(jù)標(biāo)記
    用枚舉做標(biāo)記,響應(yīng)式對(duì)象都有g(shù)et和set方法,p1初次創(chuàng)建時(shí)state沒(méi)有get和set方法,target[ReactiveFlags.IS_REACTIVE]取值為false,創(chuàng)建p3時(shí),p1響應(yīng)式,取值為true,直接返回p1
export const enum ReactiveFlags {
  IS_REACTIVE = "__v_isReactive",
}

get(target, key, receiver) {
    if (ReactiveFlags.IS_REACTIVE == key) {
      return true;
    }
    return Reflect.get(target, key, receiver);
  },

export function reactive(target) {
  ...,
  if (target[ReactiveFlags.IS_REACTIVE]) {
    return target;
  }
  const proxy = new Proxy(target, mutableHandlers);
  reactiveMap.set(target, proxy);
  return proxy;
}

2.實(shí)現(xiàn)effect

2.1 effect函數(shù)

vue2vue3早期的依賴(lài)收集采用的都是棧方式存儲(chǔ),vue3后來(lái)改為樹(shù)型數(shù)據(jù)存儲(chǔ)。
effect執(zhí)行時(shí),把當(dāng)前effect作為全局的,觸發(fā)屬性的get方法,收集依賴(lài)

let activeEffect;
class ReactiveEffect {
  public deps: Array<any> = []; // 判斷依賴(lài)屬性
  public active: boolean = true; // 是否激活
  public parent = undefined; 
  constructor(public fn) {}
  run() {
    if (!this.active) {
      return this.fn();
    }
    try {
      this.parent = activeEffect;
      activeEffect = this;
      return this.fn();
    } finally {
      activeEffect = this.parent;
      this.parent = undefined;
    }
  }
}
export function effect(fn) {
  const _effect = new ReactiveEffect(fn);
  _effect.run();
}

2.2 依賴(lài)收集

執(zhí)行effect時(shí),會(huì)觸發(fā)依賴(lài)屬性的get方法,在屬性的get中進(jìn)行依賴(lài)收集

get(target, key, receiver) {
    if (ReactiveFlags.IS_REACTIVE == key) {
      return true;
    }
    console.log(activeEffect, key);
    track(target,key)
    return Reflect.get(target, key, receiver);
  },
/* 屬性變動(dòng)后 要重新執(zhí)行run 需要把屬性和effect關(guān)聯(lián)起來(lái) 收集對(duì)象上屬性關(guān)聯(lián)的effect
 不能光記錄屬性,容易兩個(gè)對(duì)象有重名的屬性,所以需要帶著對(duì)象記錄
 target為對(duì)象
 let mapping = {
    target:{
        name:[effect1,effect2,effect3] 一個(gè)屬性可以在多個(gè)頁(yè)面使用
    }
 }
 */
const targetMap = new WeakMap();
export function track(target, key) {
  // 如果取值操作沒(méi)有發(fā)生在effect中,則不需要收集依賴(lài)
  if (!activeEffect) {
    return;
  }
  // 判斷是否已經(jīng)記錄過(guò)
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  let dep = depsMap.get(key);
  if (!dep) {
    // 值為一個(gè)不重復(fù)數(shù)組
    depsMap.set(key, (dep = new Set()));
  }
  let shouldTrack = !dep.has(key);
  if (shouldTrack) {
    dep.add(activeEffect);
    activeEffect.deps.push(dep); //同時(shí)effect記住當(dāng)前這個(gè)屬性
  }
}

2.3 屬性更改 觸發(fā)effect

 set(target, key, value, receiver) {
    // 數(shù)據(jù)變化后觸發(fā)對(duì)應(yīng)的effect方法
    const oldValue = target[key];
    let r = Reflect.set(target, key, value, receiver);
    if (oldValue != value) {
      trigger(target, key, value, oldValue);
    }
    return r;
  },
export function trigger(target, key, newValue, oldValue) {
    // 通過(guò)對(duì)象找到對(duì)應(yīng)的屬性 讓這個(gè)屬性對(duì)應(yīng)的effect重新執(zhí)行
  
    const depsMap = targetMap.get(target);
    if (!depsMap) {
      return;
    }
    const dep = depsMap.get(key); // name 或者 age對(duì)應(yīng)的所有effect
  
    const effects = [...dep];
    // 運(yùn)行的是數(shù)組 刪除的是set
    effects &&
      effects.forEach((effect) => {
        // 正在執(zhí)行的effect ,不要多次執(zhí)行
        if (effect !== activeEffect) effect.run();
      });
  }

2.4 清除effect依賴(lài)

const state = reactive({ flag: true, name: "orange", age: 18 });
      effect(() => {
        // 副作用函數(shù) (effect執(zhí)行渲染了頁(yè)面)
        console.log("render");
        document.body.innerHTML = state.flag ? state.name : state.age;
      });
      setTimeout(() => {
        state.flag = false;
        setTimeout(() => {
          console.log("修改name,原則上不更新");
          state.name = "zf";
        }, 1000);
      }, 1000);

當(dāng)切換flag時(shí),effect的依賴(lài)已經(jīng)更新,但是修改name又觸發(fā)了依賴(lài),需要在每次收集依賴(lài)前先清空
vue3源碼(二)reactive&effect,手寫(xiě)vue源碼,vue.js,javascript,前端

function cleanupEffect(effect) {
  let { deps } = effect; // 清理effect
  for (let i = 0; i < deps.length; i++) {
    deps[i].delete(effect);
  }
  effect.deps.length = 0;
}

為了避免無(wú)限循環(huán)頁(yè)面卡死情況,觸發(fā)依賴(lài)時(shí)拷貝出來(lái)一份屬性對(duì)應(yīng)的effect列表,因?yàn)榍宄臅r(shí)候在刪除effect,邊刪除邊添加會(huì)造成死循環(huán)

2.5 effect失活

通過(guò)effect返回當(dāng)前effect實(shí)例,然后curEffect.effect.stop()調(diào)用stop方法

let runner = effect(() => {
        // 副作用函數(shù) (effect執(zhí)行渲染了頁(yè)面)
        console.log("render");
        document.body.innerHTML = state.flag ? state.name : state.age;
      });
      runner.effect.stop()
  stop() {
    cleanupEffect(this);
    this.active = false;
  }

export function effect(fn) {
  const _effect = new ReactiveEffect(fn);
  _effect.run();
  const runner = _effect.run.bind(_effect); //調(diào)用effect.effect.stop() 停止effect
  runner.effect = _effect;
  return runner;
}

失活后我們可以手動(dòng)調(diào)用 runner()觸發(fā)effect方法

2.6 調(diào)度執(zhí)行

trigger觸發(fā)時(shí),我們可以自己決定副作用函數(shù)執(zhí)行的時(shí)機(jī)、次數(shù)、及執(zhí)行方式

export function effect(fn, options:any = {}) {
    const _effect = new ReactiveEffect(fn,options.scheduler); // 創(chuàng)建響應(yīng)式effect
    // if(options){
    //     Object.assign(_effect,options); // 擴(kuò)展屬性
    // }
    _effect.run(); // 讓響應(yīng)式effect默認(rèn)執(zhí)行
    const runner = _effect.run.bind(_effect);
    runner.effect = _effect;
    return runner; // 返回runner
}

export function trigger(target, type, key?, newValue?, oldValue?) {
    const depsMap = targetMap.get(target);
    if (!depsMap) {
        return
    }
    let effects = depsMap.get(key);
    if (effects) {
        effects = new Set(effects);
        for (const effect of effects) {
            if (effect !== activeEffect) { 
                if(effect.scheduler){ // 如果有調(diào)度函數(shù)則執(zhí)行調(diào)度函數(shù)
                    effect.scheduler()
                }else{
                    effect.run(); 
                }
            }
        }
    }
}

2.7 深度代理

只有當(dāng)數(shù)據(jù)被獲取的時(shí)候才進(jìn)行代理,如果獲取到的數(shù)據(jù)還是對(duì)象,繼續(xù)代理文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-823067.html

get(target, key, receiver) {
    if (ReactiveFlags.IS_REACTIVE == key) {
      return true;
    }
    track(target, key);
    let r = Reflect.get(target, key, receiver);
    if (isObject(r)) {
      return reactive(r);
    }
    return r;
  },

到了這里,關(guān)于vue3源碼(二)reactive&effect的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Vue3源碼】第五章 實(shí)現(xiàn) reactive 和 readonly 嵌套對(duì)象綁定響應(yīng)式

    【Vue3源碼】第五章 實(shí)現(xiàn) reactive 和 readonly 嵌套對(duì)象綁定響應(yīng)式

    【Vue3源碼】第五章 實(shí)現(xiàn) reactive 和 readonly 嵌套對(duì)象綁定響應(yīng)式 上一章節(jié)我們實(shí)現(xiàn)了 isReadonly 和 isReactive 兩個(gè)API。 還記得第一章時(shí)說(shuō)的proxy無(wú)法代理嵌套對(duì)象形成響應(yīng)式的問(wèn)題嗎?這一章我們實(shí)現(xiàn) reactive 和 readonly 嵌套對(duì)象轉(zhuǎn)換功能,以及shallowReadonly 和isProxy幾個(gè)簡(jiǎn)單的API。

    2024年01月18日
    瀏覽(20)
  • vue3 #ref #reactive

    一、ref 函數(shù)將簡(jiǎn)單類(lèi)型的數(shù)據(jù)包裝為響應(yīng)式數(shù)據(jù) import { ref?} from \\\'vue\\\'? const count = ref(10) 一、reactive函數(shù)將復(fù)雜類(lèi)型的數(shù)據(jù)包裝為響應(yīng)式數(shù)據(jù) import { reactive} from \\\'vue\\\'? const obj= reactive({ ? ? name : \\\'zs\\\', ? ? age : 18 })

    2024年02月22日
    瀏覽(24)
  • Vue3 ref與reactive

    Vue3 ref與reactive

    在當(dāng)今Web開(kāi)發(fā)領(lǐng)域中,構(gòu)建交互性強(qiáng)、可復(fù)用且易于維護(hù)的用戶(hù)界面是至關(guān)重要的。而Vue.js作為一款現(xiàn)代化且流行的JavaScript框架,正是為了滿(mǎn)足這些需求而誕生。它采用了MVVM架構(gòu)模式,并通過(guò)數(shù)據(jù)驅(qū)動(dòng)和組件化的方式,使我們能夠更輕松地構(gòu)建出優(yōu)雅而高效的Web應(yīng)用程序。

    2024年01月24日
    瀏覽(19)
  • vue3-響應(yīng)式基礎(chǔ)之reactive

    vue3-響應(yīng)式基礎(chǔ)之reactive

    reactive() 還有另一種聲明響應(yīng)式狀態(tài)的方式,即使用 reactive() API。與將內(nèi)部值包裝在特殊對(duì)象中的 ref 不同,reactive() 將使對(duì)象本身具有響應(yīng)性: 「點(diǎn)擊按鈕+1」 「示例效果」 響應(yīng)式對(duì)象是 JavaScript 代理,其行為就和普通對(duì)象一樣。不同的是,Vue 能夠攔截對(duì)響應(yīng)式對(duì)象所有屬

    2024年01月16日
    瀏覽(31)
  • vue3 ref 和 reactive 區(qū)別

    最近學(xué)習(xí)cloud項(xiàng)目,前端使用到 vue3 + ts 等技術(shù),在寫(xiě)需求過(guò)程中遇到 響應(yīng)式數(shù)據(jù)問(wèn)題,經(jīng)百度查找相關(guān)筆記 ,在此記錄一下,在實(shí)戰(zhàn)中成長(zhǎng)吧。 出現(xiàn)的問(wèn)題 : 定義一個(gè)默認(rèn)數(shù)組并且 for 循環(huán)展示,后端返回?cái)?shù)據(jù)并且賦值到數(shù)組中,但是展示的值并不會(huì)修改 原因 : 在 js 中

    2023年04月09日
    瀏覽(61)
  • vue3使用ref和reactive

    vue3使用ref和reactive

    目錄 ??????? vue3使用ref和reactive的方法 1.ref 2.reactive Vue 3 使用 ref 和 reactive 創(chuàng)建響應(yīng)式對(duì)象的完整示例: 1.示例 2.示例說(shuō)明 vue3使用ref和reactive的方法 Vue 3引入了兩個(gè)新的API, ref 和 reactive ,用于創(chuàng)建響應(yīng)式對(duì)象。這兩個(gè)方法都位于 Vue.prototype 上,因此可以在組件實(shí)例

    2024年02月08日
    瀏覽(29)
  • vue3 自動(dòng)引入 ref reactive...

    npm i unplugin-auto-import -D vite.config.js Q?: typescript 報(bào)錯(cuò):‘reactive’ is not defined. A :?TS 未識(shí)別到 vue api,沒(méi)有相應(yīng)的模塊聲明文件,?在 vite 中配置并生成 auto-imports.d.ts ,并在 tsconfig.json 中引入 vite.config.js tsconfig.json Q:?eslint 無(wú)法識(shí)別報(bào)錯(cuò) error ‘reactive’ is not defined no-undef A:?未配置

    2024年01月25日
    瀏覽(27)
  • Vue3 reactive丟失響應(yīng)式問(wèn)題

    Vue3 reactive丟失響應(yīng)式問(wèn)題

    問(wèn)題描述: 使用 reactive 定義的對(duì)象,重新賦值后失去了響應(yīng)式,改變值視圖不會(huì)發(fā)生變化。 測(cè)試代碼: 輸出結(jié)果: ? 從上述測(cè)試代碼中,ref 定義的對(duì)象有響應(yīng)式,而 reactive 定義的對(duì)象失去了響應(yīng)式,這是什么原因呢?官網(wǎng)中寫(xiě)到: 如果將一個(gè)對(duì)象賦值給 ref ,那么這個(gè)對(duì)

    2024年02月05日
    瀏覽(21)
  • 【Vue3響應(yīng)式入門(mén)#01】Reactivity

    【Vue3響應(yīng)式入門(mén)#01】Reactivity

    專(zhuān)欄分享:vue2源碼專(zhuān)欄,vue3源碼專(zhuān)欄,vue router源碼專(zhuān)欄,玩具項(xiàng)目專(zhuān)欄,硬核??推薦?? 歡迎各位ITer關(guān)注點(diǎn)贊收藏?????? 以下是柏成根據(jù)Vue3官方課程整理的響應(yīng)式書(shū)面文檔 - 第一節(jié),課程鏈接在此:Vue 3 Reactivity - Vue 3 Reactivity | Vue Mastery,本文檔可作為課程的輔助材料,

    2024年02月08日
    瀏覽(57)
  • Vue3的ref和reactive

    目錄 1、ref的基本使用 2、reactive的基本使用 3、ref操作dom 4、ref與reactive的異同 ref創(chuàng)建數(shù)據(jù)可以是基本類(lèi)型也可以是引用類(lèi)型 ref函數(shù)創(chuàng)建響應(yīng)式數(shù)據(jù),返回值是一個(gè)對(duì)象 模版中使用ref數(shù)據(jù),省略.value,js代碼中不能省略 獲取ref創(chuàng)建數(shù)據(jù)的值要加上.value ? reactive創(chuàng)建響應(yīng)式 reac

    2024年01月24日
    瀏覽(28)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包