欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue3中reactive和ref的實現(xiàn)與區(qū)別詳解

 更新時間:2023年10月23日 15:49:12   作者:BIBI居  
reactive和ref都是vue3實現(xiàn)響應(yīng)式系統(tǒng)的api,他們是如何實現(xiàn)響應(yīng)式的呢,reactive和ref又有什么區(qū)別呢,下面小編就來和大家詳細(xì)講講,希望對大家有所幫助

前言

reactive和ref都是vue3實現(xiàn)響應(yīng)式系統(tǒng)的api,他們是如何實現(xiàn)響應(yīng)式的呢?reactive和ref又有什么區(qū)別呢,看完這篇文章,相信答案就呼之欲出了。

effect

vue3中的reactive實現(xiàn)了數(shù)據(jù)的響應(yīng)式,說到數(shù)據(jù)響應(yīng)式離不開effect,effect是關(guān)鍵,effect()方法是暴露給創(chuàng)作者的一種方法,參數(shù)1是一個回調(diào)函數(shù),寫在回調(diào)函數(shù)的代碼可以用來模擬setup執(zhí)行函數(shù)的響應(yīng)式數(shù)據(jù)被寫在template模板的數(shù)據(jù),當(dāng)數(shù)據(jù)更新之后,將effect中的回調(diào)函數(shù)再次調(diào)用,達(dá)到數(shù)據(jù)更新便更新視圖的目的。也可以把effect叫做數(shù)據(jù)相關(guān)依賴,即記錄用到響應(yīng)式數(shù)據(jù)的代碼。參數(shù)二是一個對象,里面有l(wèi)azy屬性用來規(guī)定effect的回調(diào)函數(shù)第一次是否執(zhí)行。

<body>
    <div id="app">hello</div>
    <script>
        let data={
            name:'草原一匹狼'
        }
        effect(()=>{
            let app = document.getElementById('app')
            app.innerHTML=data.name
        },{lazy:true})
          setTimeout(()=>{
           data.name='切'
        },1000)
    </script>
</body>

實現(xiàn)effect方法,保存回調(diào)函數(shù)當(dāng)數(shù)據(jù)更新再次調(diào)用回調(diào)函數(shù)達(dá)到更新視圖

export function effect(fn, options: any = {}) {//更新視圖也就是吧視圖用到數(shù)據(jù)在執(zhí)行一遍
  const effect = createReactEffect(fn, options);
  if (!options.lazy) {//如果lazy:false執(zhí)行
    effect();
  }
  return effect;
}
let uid = 0;
//每次調(diào)用都會創(chuàng)建一個effect
let activeeffect;//設(shè)置當(dāng)前effect為全局變量好進(jìn)行收集 
let effectStack = [];//保存effect 因為可能會有多個effect
function createReactEffect(fn, options) {
  const effect = function reactiveEffect() {
    if (!effectStack.includes(effect)) {
      try {
        effectStack.push(effect);
        activeeffect = effect;
        fn();
      } finally {
        effectStack.pop();
        activeeffect = effectStack[effectStack.length - 1];
      }
    }
  };
  effect.id = uid++; //區(qū)別effect
  effect._isEffect = true; //區(qū)別effect 是不是響應(yīng)式的effect
  effect.raw = fn; //保存回調(diào)函數(shù)到自身
  effect.options = options; //保存用戶屬性lazy

  return effect;
}

reactive

了解完effect,接下來是實現(xiàn)reactive的具體過程:

  • 響應(yīng)式數(shù)據(jù)用proxy代理時get收集依賴
  • 響應(yīng)式數(shù)據(jù)用proxy代理時set執(zhí)行依賴

1.響應(yīng)式數(shù)據(jù)用proxy代理時get收集依賴

function createGetter(isReadonly = false, shall = false) {
  return function get(target, key, receiver) {
    const res = Reflect.get(target, key, receiver); //taget[key]

    if (!isReadonly) {
      //判斷是不是只讀 收集依賴
      Track(target, TackOpType.GET, key);//Track收集依賴 一個響應(yīng)式屬性key對應(yīng)一個effect保存起來
    }

    if (shall) {
      //只代理一層
      return res;
    }
    if (isObject(res)) {
      return isReadonly ? readonly(res) : reactive(res);
    }
    return res;
  };
}
//收集effect 獲取數(shù)據(jù)觸發(fā)get 收集依賴數(shù)據(jù)變化更新視圖 key和effect11對應(yīng)
let targetMap = new WeakMap(); //棧結(jié)構(gòu)(target ,new Map(key(key effect一一對應(yīng)),new Set(activeeffect)))
export function Track(target, type, key) {
  //對應(yīng)的key
  if (activeeffect == undefined) {
    return;
  }
  let depMAp = targetMap.get(target);
  if (!depMAp) {
    targetMap.set(target, (depMAp = new Map()));
  }
  let dep = depMAp.get(key);
  if (!dep) {
    depMAp.set(key, (dep = new Set()));
  }
  if (!dep.has(activeeffect)) {
    dep.add(activeeffect);
  }
}

2.響應(yīng)式數(shù)據(jù)用proxy代理時set執(zhí)行依賴

function createSetter(shall = false) {
  return function set(target, key, value, receive) {
    const oldValue = target[key];

    let hasKey =
      Array.isArray(oldValue) && isIntegerKey(key)
        ? Number(key) < target.length
        : hasOwn(target, key);
    const result = Reflect.set(target, key, value, receive); //獲取最新的值 對象數(shù)據(jù)已經(jīng)更新
    if (!hasKey) {
      // 新增
      trigger(target, TriggerOpTypes.ADD, key, value);
    } else {
      // 修改數(shù)組
      if (hasChange(value, oldValue)) {
        trigger(target, TriggerOpTypes.SET, key, value, oldValue);
      }
    }

    return result;
  };
}
//觸發(fā)更新依賴effect
export function trigger(target, type, key?, newValue?, oldValue?) {
  const depsMap = targetMap.get(target);
  let effectSet = new Set();
  if (!depsMap) return;
  const add = (effectAdd) => {
    if (effectAdd) {
      effectAdd.forEach((effect) => effectSet.add(effect));
    }
  };
  add(depsMap.get(key)); //獲取當(dāng)前屬性的effect
  //處理數(shù)組
  if (key == "length" && Array.isArray(target)) {
    depsMap.forEach((dep, key) => {
      if (key === "length" || key >= newValue) {
        add(dep);
      }
    });
  }else{
    //處理對象
    if(key !== undefined){
      add(depsMap.get(key))
    }
    switch(type){
      case TriggerOpTypes.ADD: 
      if(Array.isArray(target)&& isIntegerKey(key)){
        add(depsMap.get('target'))
      }
    }
  }
  effectSet.forEach((effect: any) => {
    if(effect.options.sch){
      effect.options.sch(effect)
    }else{
      effect()
    }
  });
  • 被reactive包裹的數(shù)據(jù)實現(xiàn)響應(yīng)式,首先得effec保存回調(diào)函數(shù),方便數(shù)據(jù)更新再次調(diào)用來更新視圖,
  • 當(dāng)用proxy對對象代理時get方法中將視圖用到的代碼片段即相關(guān)effect與key一一對應(yīng)保存起來
  • 當(dāng)數(shù)據(jù)改變用到proxy的set方法時,用key找到對應(yīng)effect執(zhí)行

ref

相信大家都知道用reactive實現(xiàn)復(fù)雜數(shù)據(jù)代理用ref實現(xiàn)簡單數(shù)據(jù)的代理,因為vue用es6的proxy代理整個對象,而ref是給簡單數(shù)據(jù)用一個對象包裹起來用object.defineproperty方式代理并且用.value訪問,如果用ref對一個對象進(jìn)行響應(yīng)式處理則會調(diào)用crtoReactive方法再次對.value的屬性進(jìn)行代理。 根據(jù)上面已經(jīng)實現(xiàn)的reactive api實現(xiàn)ref就簡單多了。

具體步驟為:

1.如果是簡單數(shù)據(jù)就用object.defineproperty代理

2.如果是復(fù)雜數(shù)據(jù)就用createReactive方法再次代理

export function ref(target){
    return creatRef(target)
}

//創(chuàng)建實例對象
class RefImpl{
    public _v_isRef=true
    public _value
    
    public _shallow
    public _rawValue
    constructor(public target,public shallow){
        this._shallow=shallow
        this._rawValue = shallow ? target : toRaw(target)
        this._value = shallow ? target : toReactive(target)
    }
    get value(){
        Track(this,TackOpType.GET,"value")
        return this.value
    }
    set value(newVAlue){
        if(newVAlue!==this._value)
         this._rawValue=newVAlue 
         this._value = isObject(newVAlue) ? newVAlue : toReactive(newVAlue)//這是ref不失去響應(yīng)式的關(guān)鍵如果新的值就重新代理
        trigger(this,TriggerOpTypes.SET,"value",newVAlue)


    }
}
function creatRef(target,shallow=false){
    //創(chuàng)建ref實例對象
    return new RefImpl(target,shallow)
}

到此這篇關(guān)于vue3中reactive和ref的實現(xiàn)與區(qū)別詳解的文章就介紹到這了,更多相關(guān) vue3 reactive ref內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue+vuex+axios+echarts畫一個動態(tài)更新的中國地圖的方法

    vue+vuex+axios+echarts畫一個動態(tài)更新的中國地圖的方法

    本篇文章主要介紹了vue+vuex+axios+echarts畫一個動態(tài)更新的中國地圖的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Vue.js添加組件操作示例

    Vue.js添加組件操作示例

    這篇文章主要介紹了Vue.js添加組件操作,結(jié)合實例形式分析了vue.js組件的注冊、調(diào)用相關(guān)操作技巧,需要的朋友可以參考下
    2018-06-06
  • vue-cli 自定義指令directive 添加驗證滑塊示例

    vue-cli 自定義指令directive 添加驗證滑塊示例

    本篇文章主要介紹了vue-cli 自定義指令directive 添加驗證滑塊示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • 解決vue2中使用axios http請求出現(xiàn)的問題

    解決vue2中使用axios http請求出現(xiàn)的問題

    下面小編就為大家分享一篇解決vue2中使用axios http請求出現(xiàn)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • vue實現(xiàn)虛擬列表組件解決長列表性能問題

    vue實現(xiàn)虛擬列表組件解決長列表性能問題

    這篇文章主要介紹了在vue中實現(xiàn)虛擬列表組件,解決長列表性能問題,本文給大家分享實現(xiàn)思路及實例代碼,需要的朋友可以參考下
    2022-07-07
  • 在vue框架下使用指令vue add element安裝element報錯問題

    在vue框架下使用指令vue add element安裝element報錯問題

    這篇文章主要介紹了在vue框架下使用指令vue add element安裝element報錯問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 在IDEA中安裝vue插件全過程

    在IDEA中安裝vue插件全過程

    這篇文章主要介紹了在IDEA中安裝vue插件全過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Laravel 如何在blade文件中使用Vue組件的示例代碼

    Laravel 如何在blade文件中使用Vue組件的示例代碼

    這篇文章主要介紹了Laravel 如何在blade文件中使用Vue組件,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • 圖文詳解keep-alive如何清除緩存

    圖文詳解keep-alive如何清除緩存

    vue項目中常常會用到keepalive來作緩存,在應(yīng)付基本要求上能夠說很是方便,可是遇到同一個頁面,根據(jù)條件不一樣,分別緩存或者不緩存,就有些麻煩了,這篇文章主要給大家介紹了關(guān)于keep-alive如何清除緩存的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • Vue中的transition封裝組件的實現(xiàn)方法

    Vue中的transition封裝組件的實現(xiàn)方法

    這篇文章主要介紹了Vue中的transition封裝組件的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08

最新評論