當前位置: 妍妍網 > 碼農

有人抵觸ref?有人抵觸reactive?

2024-05-05碼農

模擬面試、簡歷指導、入職指導、計畫指導、答疑解惑 可私信找我~已幫助100+名同學完成改造!

前言

大家好,我是林三心,用最通俗易懂的話講最難的知識點是我的座右銘,基礎是進階的前提是我的初心~

背景

這幾天看到好多文章標題都是類似於:

  • 不用 ref 的 xx 個理由

  • 不用 reactive 的 xx 個理由

  • 歷數 ref 的 xx 宗罪

  • 我就很不解,到底是什麽原因導致有這兩批人:

  • 抵觸 ref 的人

  • 抵觸 reactive 的人

  • 看了這些文章,我可以總結出他們的想法

    抵觸 reactive 的人

    抵觸 reactive 的人,他們的想法大概就是:

  • 1、 Vue 官方推薦 ref

  • 2、 reactive 有型別限制,ref 沒有

  • 3、 reactive 使用不當會遺失響應式,比如解構

  • 4、 reactive 無法修改整個物件的值

  • 抵觸 ref 的人

    抵觸 ref 的人,他們的想法大概就是:

  • 1、 ref 的底層其實就是 reactive,用 ref 相當於多了一層,耗費效能

  • 2、 ref 的 .value 用起來很麻煩,增加使用者心裏負擔

  • 3、 ref 到樣版的時候會解掉 value 這一層,這時候也會耗費效能

  • 把我整笑了~

    說實話,看到這些文章,有點把我整笑了,其實你要用 ref 或者 reactive 都沒錯,但是沒比必要那麽抵觸,編程很多時候並不是非黑即白啊。。。

    既然 Vue3 推出了 ref 和 reactive,那就說明他們都有存在的必要,在計畫中不同的場景去運用他們,我覺得才是最好的,而不是用一個不用另一個,不止這兩個,還有很多其他好用的 Vue3 API

    我想針對這兩批人的想法做一個回應:

    回應 -> 抵觸 reactive 的人

  • 1、官方是推薦,不是抵觸

  • 2、reactive 既然有型別限制,那就在特定時候用 reactive 就行

  • 3、使用不當會遺失響應式?那就是開發者對於 Vue3 API 的使用還不熟

  • 4、用 Object.assign 就可以修改整個物件的值

  • 回應 -> 抵觸 ref 的人

  • 1、耗費效能的話,這麽久了,也沒人貼出到底耗費了多少效能?

  • 2、.value 不麻煩,我覺得 .value 可以起到辨別響應式和非響應式數據的效果,而且現在編輯器都有外掛程式提供的程式碼補全了,多個 .value 也花不了多少時間吧?

  • 靈活使用 Vue3 API 才是王道

    其實在平時開發中,我覺得基本數據型別和陣列,都可以用 ref 來管理,而物件的話可以使用 reactive 來管理,比如表單物件、狀態物件

    其實 Vue3 不止有這兩個 API ,還有很多其他 API ,也很好用,大家只要去靈活使用它們,能讓你的Vue3 計畫上一個層次

    readonly

    顧名思義,就是唯讀的意思,如果你的數據被這個 API 包裹住的話,那麽修改之後並不會觸發響應式,並且會提示警告

    readonly 的用途一般用於一些 hooks 暴露出來的變量,不想外界去修改,比如我封裝一個 hooks,這樣去做的話,那麽外界只能用變量,但是不能修改變量,這樣大大保護了 hooks 內部的邏輯~

    shallowRef

    shallowRef 用來包住一個基礎型別或者參照型別,如果是基礎型別那麽跟 ref 基本沒區別,如果是參照型別的話,那麽直接改深層內容是不能觸發響應式的,除非直接修改參照地址,如下:

    註意:改深層屬效能改數據,只是沒觸發響應式,所以當下一次響應式觸發的時候,你修改的深層數據會渲染到頁面上~

    shallowRef 的用處主要用於一些比較大的但又變化不大的數據,比如我有一個表格數據,透過介面直接獲取,並且主要用在前端展示,需要修改一些深層的內容,但是這些內容並不需要立即表現在頁面上,比如以下例子,我只需要展示 name、age 欄位,至於 isOld 欄位並不需要展示,我想要計算 isOld 但是又不想觸發響應式更新,所以可以用 shallowRef 包起來,進而減少響應式更新,最佳化效能

    shallowReactive

    shallowReactive 用來包住一個參照型別,被包住後,修改第一層才會觸發響應式更新,也就是淺層的內容,修改深層的內容並不會觸發響應式更新

    註意:改深層屬效能改數據,只是沒觸發響應式,所以當下一次響應式觸發的時候,你修改的深層數據會渲染到頁面上~

    shallowReactive 用的比較少,shallowReactive 的用處跟 shallowRef 比較像,都是為了讓一些比較大的數據能減少響應式更新,進而最佳化效能

    toRef & toRefs

    先說說 toRef 吧,我們平時在使用 reactive 的時候會有一個苦惱,那就是解構,比如看以下例子,我們為了少些一些程式碼,解構出來了 name 並放到樣版裏渲染,但是當我們想改原數據的時候,發現 name 並不會更新,這就是解構出來基礎型別的苦惱

    這時我們可以使用 toRef,這個時候我們直接修改 name 也會觸發原數據的修改,修改原數據也會觸發 name 的修改

    但是如果是內容太多了,我們想一個一個去用 toRef 的話會寫很多程式碼

    所以我們可以使用 toRefs 一次性解構

    toRaw & markRaw & unref

    toRaw 可以把一個響應式 reactive 轉成普通物件,也就是把響應式物件轉成非響應式物件

    toRaw 主要用在回呼傳參中,比如我封裝一個 hooks,我想要把 hooks 內維護的響應式變量轉成普通數據,當做參數傳給回呼函式,可以用 toRaw

    markRaw 可以用來標記響應式物件裏的某個內容不被追蹤,如果你的響應式物件裏有某個內容數據量比較大,但又不想被追蹤,你可以使用 markRaw

    unref 相當於返回 ref 的 value

    effectScope & onScopeDispose

    effectScope 可以有兩個作用:

  • 收集副作用

  • 全域狀態管理

  • 收集副作用

    比如我們封裝一個共用的 hooks,為了減少頁面隱患,肯定會統一收集副作用,並且在元件銷毀的時候去統一消除,比如以下程式碼:

    但是這麽收集很麻煩, effectScope 能幫我們做到統一收集,並且透過 stop 方法來進行清除,且 stop 執行的時候會觸發 effectScope 內部的 onScopeDispose

    我們可以利用 effectScope & onScopeDispose 來做一些效能最佳化,比如下面這個例子,我們封裝一個滑鼠監聽的 hooks

    但是如果在頁面裏呼叫多次的話,那麽勢必會往 window 身上監聽很多多余的事件,造成效能負擔,所以解決方案就是,無論頁面裏呼叫再多次 useMouse,我們只往 window 身上加一個滑鼠監聽事件

    全域狀態管理

    現在 Vue3 最火的全域狀態管理工具肯定是 Pinia 了,那麽你們知道 Pinia 的原理是什麽嗎?原理就是依賴了 effectScope

    所以我們完全可以自己使用 effectScope 來實作自己的局部狀態管理,比如我們封裝一個通用元件,這個元件層級比較多,並且需要共享一些數據,那麽這個時候肯定不會用 Pinia 這種全域狀態管理,而是會自己寫一個局部的狀態管理,這個時候 effectScope 就可以排上用場了

    vueuse 中的 createGlobalState 就是為了這個而生

    provide & inject

    Vue3 用來提供註入的 API,主要是用在元件的封裝,比如那種層級較多的元件,且子元件需要依賴父元件甚至爺爺元件的數據,那麽可以使用 provide & inject,最典型的例子就是 Form 表單元件,可以去看看各個元件庫的源碼,表單元件大部份都是用 provide & inject 來實作的,比如 Form、Form-Item、Input這三個需要互相依賴對方的規則、欄位名、欄位值,所以用 provide & inject 會更好。具體用法看文件吧~https://cn.vuejs.org/guide/components/provide-inject.html

    結語

    我是林三心

  • 一個待過 小型toG型外包公司、大型外包公司、小公司、潛力型創業公司、大公司 的作死型前端選手;

  • 一個偏前端的全幹工程師;

  • 一個不正經的金塊作者;

  • 逗比的B站up主;

  • 不帥的小紅書博主;

  • 喜歡打鐵的籃球菜鳥;

  • 喜歡歷史的乏味少年;

  • 喜歡rap的五音不全弱雞如果你想一起學習前端,一起摸魚,一起研究簡歷最佳化,一起研究面試進步,一起交流歷史音樂籃球rap,可以來俺的摸魚學習群哈哈,點這個,有7000多名前端小夥伴在等著一起學習哦 -->

  • 廣州的兄弟可以約飯哦,或者約球~我負責打鐵,你負責進球,謝謝~