<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Vue3 糟糕透頂 Api——Reactivity

          共 7225字,需瀏覽 15分鐘

           ·

          2021-08-17 14:13

          看到標(biāo)題,小伙伴們是不是很驚訝?也許會(huì)聯(lián)想到Reactivity是不是設(shè)計(jì)上有缺陷?其實(shí)是醉翁之意不在酒!Reactivity可以說(shuō)是vue3中最復(fù)雜的一個(gè)地方,當(dāng)然也是功能最強(qiáng)大的一個(gè)點(diǎn),聽起來(lái)是塊硬骨頭哈??,這讓我想起亮劍中李云龍面對(duì)小日本挑釁說(shuō)的話:就是閻王爺來(lái)了,我也得摟他幾根胡子下來(lái)。那么今天咱們也摟摟Reactivity的胡子。

          在vue3當(dāng)中,它是把數(shù)據(jù)響應(yīng)式Api全都暴露出來(lái)了,在vue2中是沒(méi)有這樣做的,那vue2是怎么做的呢?它是將數(shù)據(jù)配置到data當(dāng)中,data中的數(shù)據(jù)會(huì)自動(dòng)變成響應(yīng)式數(shù)據(jù),我們把這個(gè)過(guò)程叫做注入,它會(huì)注入到組件實(shí)例當(dāng)中去,如下:

          {
          //data中的數(shù)據(jù)都是響應(yīng)式的,會(huì)被注入到組件實(shí)例當(dāng)中
          data(){
          return{
          name:"法醫(yī)",
          idol:"喬布斯",
          publicNumber:"前端獵手"
          }
          }
          }

          然而在vue3中,它不再是data了,而是setup函數(shù),我們把它稱之為composition Api,我們要在setup函數(shù)中使用響應(yīng)式數(shù)據(jù),就不可避免需要暴露出響應(yīng)式的Api供我們使用,接下來(lái),我們來(lái)看看vue3提供了哪些跟數(shù)據(jù)響應(yīng)式相關(guān)的函數(shù)。

          ?? 獲取響應(yīng)式數(shù)據(jù)

          可以獲取響應(yīng)式數(shù)據(jù)的api:

          • reactive

            這個(gè)api會(huì)傳入一個(gè)對(duì)象,然后返回一個(gè)對(duì)象代理proxy,并且它是可以深度代理對(duì)象中的所有成員的,也就是說(shuō)對(duì)象里面再嵌套一個(gè)對(duì)象,也是響應(yīng)式的數(shù)據(jù)

            舉個(gè)栗子??:

            import { reactive } from'vue'
            const state = reactive({name:"法醫(yī)",age:18})
            window.state = state;

            效果展示:

            24b8d0665833935c011bb028ccfb8f0a.webpimage.png

            現(xiàn)在這個(gè)對(duì)象就變成響應(yīng)式的了,對(duì)對(duì)象進(jìn)行操作,vue就可以收到通知了

          • readonly

            這個(gè)api需要傳入一個(gè)對(duì)象或者是一個(gè)代理,同樣也會(huì)返回一個(gè)對(duì)象代理,它只能讀取代理對(duì)象中的成員,而不能修改,也就是只能get,不可以set,它也是可以深度代理對(duì)象中所有成員的。

            舉個(gè)栗子??:

            import { reactive,readonly } from'vue'
            const imState = readonly({name:"法醫(yī)",age:18})
            window.imState = imState;

            效果展示:

            ef098ab54bcc24451f786a6571f31e98.webp

            看見沒(méi),報(bào)了一個(gè)錯(cuò)誤,提示說(shuō)要修改的目標(biāo)是只讀的,修改失敗

            剛才有說(shuō)readonly可以傳一個(gè)對(duì)象,也可以傳一個(gè)代理,我們?cè)倏纯磦饕粋€(gè)代理會(huì)怎么樣

            import { reactive,readonly } from'vue'
            const state = reactive({name:"法醫(yī)",age:18})
            const imState = readonly(state);//傳一個(gè)代理進(jìn)去
            window.imState = imState;

            效果展示:

            aca612ea64be7362be88c6e3b69a99e1.webp

            傳一個(gè)代理的時(shí)候也是不可以進(jìn)行賦值操作的,反正只要經(jīng)過(guò)readonly后就只能讀不能賦值,但是,我們可以在readonly之前修改值,然后讓它進(jìn)行代理就可以了。

            ??注意:reactivereadonly,這兩個(gè)api是代理對(duì)象的,是沒(méi)辦法代理普通值的,會(huì)報(bào)錯(cuò)

            舉個(gè)栗子??:

            import { reactive,readonly } from'vue'
            const state = reactive("法醫(yī)")

            效果展示:

            c64cc870bd76c628b4f3550a6a5ed95c.webp

            報(bào)了一個(gè)警告,原始值是沒(méi)法代理的,那么如果需要代理普通值,那該咋辦呢?那就要用到refapi了

          • ref

            ref中可以傳入任何數(shù)據(jù),最終會(huì)將數(shù)據(jù)放到一個(gè)對(duì)象中的value中,比如這種{ value : ...},對(duì)value的訪問(wèn)是響應(yīng)式的,如果給value的值是一個(gè)對(duì)象的話,它會(huì)通過(guò)reactive函數(shù)進(jìn)行代理

            舉個(gè)栗子??:

            import { reactive,readonly,ref } from'vue'
            const state = ref({name:"法醫(yī)",age:18})
            window.state = state;

            效果展示:

            0059ebe882606375bc5f4109f23f633e.webp

            還有一種情況是:如果說(shuō)傳入的value值已經(jīng)是代理了,那么會(huì)直接使用代理

            舉個(gè)栗子??:

            import { reactive,readonly,ref } from'vue'
            const state = reactive({name:"法醫(yī)",age:18});
            const imState = ref(state)
            window.imState = imState;

            效果展示:

            b2c73f2da3398ab206081b35c6a5d86d.webp
          • computed

            computed需要傳入一個(gè)函數(shù)function,它返回的值跟ref一樣,也是{value:...},當(dāng)讀取value值的時(shí)候,它會(huì)根據(jù)情況決定是否要運(yùn)行函數(shù),這個(gè)情況就是有沒(méi)有用到這個(gè)函數(shù),并且它是有緩存的,當(dāng)依賴的響應(yīng)式數(shù)據(jù)沒(méi)有變化的時(shí)候,拿到的是緩存里面的值,只有當(dāng)state.name或者state.age發(fā)生改變時(shí)才會(huì)重新運(yùn)行。

            舉個(gè)栗子??:

            import { reactive,readonly,ref ,computed} from'vue'
            const state = reactive({name:"法醫(yī)",age:18})

            const result = computed(()=>{
            console.log("computed");
            return state.name + state.age
            })
            console.log(result.value);

            效果展示:

            adccf1262c0427b422ab76d9c95ec0bf.webp

            反正以上四個(gè)api不管它怎么進(jìn)行處理,就一個(gè)目的,那就是把數(shù)據(jù)變成響應(yīng)式數(shù)據(jù)。

            那么在開發(fā)中到底用哪個(gè)?

            ?? 注意:用ref的時(shí)候要拿到數(shù)據(jù)必須是ref.value哈,不然拿不到,切記!??

          1. 如果想要一個(gè)對(duì)象變?yōu)轫憫?yīng)式數(shù)據(jù),可以使用reactive或者ref
          2. 如果說(shuō)讓對(duì)象所有屬性只能讀,就用readonly
          3. 如果想讓一個(gè)非對(duì)象數(shù)據(jù)變成響應(yīng)式數(shù)據(jù),就用ref
          4. 如果想要根據(jù)已知的響應(yīng)式數(shù)據(jù)得到一個(gè)新的響應(yīng)式數(shù)據(jù),就用computed

          ?? 監(jiān)聽數(shù)據(jù)變化

          • watchEffect
          const stop = watchEffect(() => {
          //watchEffect 函數(shù)會(huì)立即執(zhí)行,然后監(jiān)聽函數(shù)中會(huì)用到的響應(yīng)式數(shù)據(jù),響應(yīng)式數(shù)據(jù)變化后會(huì)再次執(zhí)行
          })

          //通過(guò)調(diào)用stop函數(shù)就會(huì)停止監(jiān)聽
          stop();//停止監(jiān)聽

          舉個(gè)栗子??:

          import { reactive, ref, watchEffect } from"vue";

          const state = reactive({a: 1,b: 2,});
          const count = ref(0);

          watchEffect(() =>{
          console.log(state.a,count.value);//先會(huì)立即執(zhí)行一次
          })

          state.a++;//這里依賴數(shù)據(jù)改變?cè)俅螆?zhí)行一次

          效果展示:

          9243583d5d453ab5c57b294ebfb0d773.webp

          watchEffect函數(shù)之所以知道依賴變化了,是因?yàn)槔锩娴臄?shù)據(jù)是響應(yīng)式的,當(dāng)讀取數(shù)據(jù)的時(shí)候用的是get方法,get會(huì)收集依賴。還要注意的是如果說(shuō)依賴的數(shù)據(jù)同時(shí)改變很多次,最終結(jié)果是會(huì)顯示一次,因?yàn)檫\(yùn)行過(guò)程是異步的,是會(huì)到微隊(duì)列中執(zhí)行的,等數(shù)據(jù)變完之后才會(huì)運(yùn)行,如下例子:

          舉個(gè)栗子??:

          import { reactive, ref, watchEffect } from"vue";

          const state = reactive({a: 1,b: 2,});
          const count = ref(0);

          watchEffect(() =>{
          console.log(state.a,count.value);
          })
          //運(yùn)行多次
          state.a++;
          state.a++;
          state.a++;
          state.a++;
          state.a++;
          state.a++;
          state.a++;
          state.a++;

          效果展示:

          b790e8a83e439535159ca87172c1ce0c.webp

          從最終結(jié)果可以看出最終只運(yùn)行兩次,一次是立即執(zhí)行,第二次是數(shù)據(jù)改變后

          • watch

          這個(gè)watch相當(dāng)于vue2的$watch,這個(gè)watch有點(diǎn)麻煩,因?yàn)樗枰謩?dòng)去指定監(jiān)控哪些值的變化,當(dāng)變化的時(shí)候,它會(huì)把新的值舊的值同時(shí)給你

          舉個(gè)栗子??:

          import { reactive, ref, watch } from"vue";

          const state = reactive({a: 1,b: 2,});
          const count = ref(0);

          watch(()=>state.a,(newValue,oldValue) =>{
          console.log("新值",newValue,"舊值",oldValue);
          })
          state.a++;//修改依賴

          效果展示:

          0b595cc45b0ab5d811c28f3fe7bc6d96.webp

          ?? 注意:在這里需要注意的是watchwatchEffect不同的是watch不會(huì)立即運(yùn)行函數(shù),只有當(dāng)依賴的值改變時(shí)才會(huì)執(zhí)行,watch中會(huì)傳兩個(gè)參數(shù),在上面例子中傳的是()=>state.a,那為什么不直接傳state.a呢?如果直接傳state.a的話,那么相當(dāng)于傳了一個(gè)1進(jìn)去,這樣數(shù)據(jù)就不是響應(yīng)式的了,如下:

          舉個(gè)栗子??:?直接傳state.a

          import { reactive, ref, watch } from"vue";

          const state = reactive({a: 1,b: 2,});
          const count = ref(0);

          watch(state.a,(newValue,oldValue) =>{
          console.log("新值",newValue,"舊值",oldValue);
          })
          state.a++;//修改依賴

          效果展示:

          1b2bcd88b17509d420e4d640a874a375.webp

          如果直接傳state.a,這里就會(huì)報(bào)警告,翻譯過(guò)來(lái)是:無(wú)效的監(jiān)視源:1監(jiān)視源只能是getter/effect函數(shù)、ref、被動(dòng)對(duì)象或這些類型的數(shù)組,意思就是說(shuō)這里參數(shù)只能是響應(yīng)式數(shù)據(jù)。

          當(dāng)傳一個(gè)()=>state.a函數(shù)進(jìn)去,它是在watch里面運(yùn)行的,這樣就會(huì)收集依賴。當(dāng)使用reactiveapi的時(shí)候就要傳一個(gè)這樣函數(shù)進(jìn)去,當(dāng)使用refapi的時(shí)候,watch中第一個(gè)參數(shù)可以寫成count,因?yàn)閏ount是一個(gè)對(duì)象,如下:

          舉個(gè)栗子??:?直接傳count

          import { reactive, ref, watch } from"vue";

          const state = reactive({a: 1,b: 2,});
          const count = ref(0);

          watch(count,(newValue,oldValue) =>{
          console.log("新值",newValue,"舊值",oldValue);
          })
          count.value++;//修改依賴

          效果展示:

          14da541d47cfdb59afe1f1bdf0ab70c3.webp

          如果說(shuō)傳了一個(gè)count.value進(jìn)去,那么也會(huì)報(bào)錯(cuò),因?yàn)閏ount.value拿到的也是屬性值了,如下:

          舉個(gè)栗子??:?直接傳count

          import { reactive, ref, watch } from"vue";

          const state = reactive({a: 1,b: 2,});
          const count = ref(0);

          watch(count.value,(newValue,oldValue) =>{
          console.log("新值",newValue,"舊值",oldValue);
          })
          count.value++;//修改依賴

          效果展示:

          fbff65b57509dd955896554895f4ab96.webp

          從運(yùn)行結(jié)果看,也報(bào)了一個(gè)警告,所以說(shuō)這塊得注意下??

          對(duì)了,差點(diǎn)忘了,watch是可以監(jiān)控多個(gè)數(shù)據(jù)的,如下:

          舉個(gè)栗子??:?傳count()=>state.a

          import { reactive, ref, watch } from"vue";

          const state = reactive({a: 1,b: 2,});
          const count = ref(0);

          watch([()=>state.a,count],([newValue1,newValue2],[oldValue1,oldValue2]) =>{
          console.log("新值",newValue1,newValue2,"舊值",oldValue1,oldValue2);
          })
          count.value++;
          state.a++;

          效果展示:

          563fb77b1781cfc5bae236c6623cbe88.webp

          ?? 注意:無(wú)論是watch還是watchEffect,當(dāng)依賴變化時(shí),回調(diào)函數(shù)都是異步執(zhí)行的,當(dāng)然也會(huì)到微隊(duì)列等待執(zhí)行。

          總得來(lái)說(shuō)watchEffect是最方便的,因?yàn)樗鼤?huì)自動(dòng)跟蹤依賴的變化,不需要手動(dòng)指定,但是有時(shí)候卻不得不使用watch,比如說(shuō):我們不希望回調(diào)函數(shù)一開始就執(zhí)行,只想讓它當(dāng)數(shù)據(jù)改變的時(shí)候才執(zhí)行,這時(shí)候就只能用watch了,還有一種就是數(shù)據(jù)改變時(shí),我們需要知道舊值是什么?這時(shí)也需要使用watch,最后一種就是我們需要監(jiān)控一些回調(diào)函數(shù)中用不到的數(shù)據(jù),比方說(shuō),輸出console.log("我要變了"),這在watchEffect中是做不到的

          ?? 判斷

          在獲取響應(yīng)式數(shù)據(jù)的時(shí)候有四種api,分別是reactive、readonly、ref、computed,返回有兩種形式,一個(gè)是對(duì)象代理,另一個(gè)是{value:...}這種形式,有時(shí)候我們可能沒(méi)睡醒,大腦混亂,于是vue3提供了4種api用于區(qū)分到底是哪種方式獲取的響應(yīng)式數(shù)據(jù):

          • isProxy : 用于判斷某個(gè)數(shù)據(jù)是否是由reactivereadonly獲取的

          • isReative : 判斷某個(gè)數(shù)據(jù)是否是通過(guò)reative創(chuàng)建的,具體可以看這個(gè)鏈接:?v3.vuejs.org/api/basic-r…[1]

          • isReadonly :判斷某個(gè)數(shù)據(jù)是否是通過(guò)readonly創(chuàng)建的

          • isRef :判斷某個(gè)數(shù)據(jù)是否是一個(gè)ref對(duì)象

          ?? 轉(zhuǎn)換

          有時(shí)候我們拿到一個(gè)數(shù)據(jù),我們也不知道它是個(gè)啥,可能有時(shí)候也顧不上,到底是ref呢,還是proxy,鬼都不知道它是個(gè)啥!

          這時(shí)我們可以用unref

          • unref

          unref?等同于:isRef(val) ? val.value : val,如果是ref的話那就把val.value值拿出來(lái),如果不是就拿val

          舉個(gè)栗子??:

          function useNewTodo(todos){
          todos = unref(todos);
          //...其它代碼
          }

          • toRef

          toRef會(huì)把一個(gè)響應(yīng)式對(duì)象中的某個(gè)屬性變成ref格式的數(shù)據(jù)

          舉個(gè)栗子??:

          import { reactive,  toRef } from"vue";

          const state = reactive({ name: "法醫(yī)", age: 18 });

          const nameRef = toRef(state,"name");

          console.log(nameRef);//最終是 {value:...}這種形式

          nameRef.value = "前端獵手";//當(dāng)修改這個(gè)值后,state里面的數(shù)據(jù)也會(huì)受到影響
          console.log(state.name);

          效果展示:

          12e79a86326c9e424e2ef7db3f1776f3.webp
          • toRefs

          把一個(gè)響應(yīng)式對(duì)象的所有屬性轉(zhuǎn)換為ref格式,然后包裝到plain-object普通對(duì)象中返回

          舉個(gè)栗子??:

          import { reactive, toRefs } from"vue";

          const state = reactive({ name: "法醫(yī)", age: 18 });

          const stateAsRefs = toRefs(state);
          console.log(stateAsRefs);

          /*
          stateAsRefs 它不是一個(gè)代理對(duì)象了,而是一個(gè)普通對(duì)象,如下格式:
          {
          name:{value:ObjectRefImpl},
          age:{value:ObjectRefImpl}
          }
          */


          效果展示:

          51db57e94ffbfedb8dde0d4842306d80.webp

          為什么要這么做?

          舉個(gè)栗子??:?我們需要把兩個(gè)響應(yīng)式數(shù)據(jù)混合在一起,如果直接使用展開運(yùn)算符那么就完蛋了,數(shù)據(jù)會(huì)失去響應(yīng)式

          setup() {
          const state1 = reactive({a:1,b:2});
          const state2 = reactive({c:3,d:4});
          return {
          ...state1,// 失去響應(yīng)式,相當(dāng)于在這寫了一個(gè)a:1,b:2
          ...state2,// 失去響應(yīng)式,相當(dāng)于在這寫了一個(gè)c:3,d:4
          };
          },

          那么如何解決呢?外面套一個(gè)toRefs就好了

          setup() {
          const state1 = reactive({a:1,b:2});
          const state2 = reactive({c:3,d:4});
          return {
          ...toRefs(state1),// 具有響應(yīng)式
          ...toRefs(state2),// 具有響應(yīng)式
          };
          },

          參考資料

          [1]

          https://v3.vuejs.org/api/basic-reactivity.html#isreactive:?https://link.juejin.cn?target=https%3A%2F%2Fv3.vuejs.org%2Fapi%2Fbasic-reactivity.html%23isreactive



          最后



          如果你覺(jué)得這篇內(nèi)容對(duì)你挺有啟發(fā),我想邀請(qǐng)你幫我三個(gè)小忙:

          1. 點(diǎn)個(gè)「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點(diǎn)在看,都是耍流氓 -_-)

          2. 歡迎加我微信「?sherlocked_93?」拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...

          3. 關(guān)注公眾號(hào)「前端下午茶」,持續(xù)為你推送精選好文,也可以加我為好友,隨時(shí)聊騷。


          3938879b525d82af0066e1fbd9767e91.webp點(diǎn)個(gè)在看支持我吧,轉(zhuǎn)發(fā)就更好了



          瀏覽 47
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  秋霞欧美性爱 | 日本足交 | 911在线无码精品秘 入口楼风 | 国产高清自拍视频 | 欧美日韩国产成人电影 |