《前端會客廳》對話winter和尤雨溪,深度探尋Vue3設計思想(中)

前端會客廳第一期(中)B站地址javascript

前端會客廳是我和winter設計的一檔技術節目,每期會邀請一個嘉賓,暢聊前端技術,廢話很少說,尤大上篇很受歡迎,中篇也上線拉,配套代碼演示 至關於一個買家秀, 代碼實操我最近會錄製視頻放B站,歡迎關注html

TOC

  1. Composition API
    1. reactive
    2. watchEffect
    3. ref
  2. 響應式 && LocalStorage
  3. 響應式 && 數據獲取
  4. Option Vs Composition

Composition

其實Vue2如今就有一個全局的方法,方法叫作Vue.observable。 這個其實就是跟Vue3的這個reactive,是同樣的,前端

it('should observe basic properties', () => {
    let dummy
    const counter = reactive({ num: 0 })
    effect(() => (dummy = counter.num))

    expect(dummy).toBe(0)
    counter.num = 7
    expect(dummy).toBe(7)
  })

複製代碼

reactive負責對象等負責數據,ref負責基本數據變成響應式 好比數字和字符串,effect負責反作用,這三個概念就是響應式的核心,並且ref和reactive還有一點點小區別vue

reactive直接遍歷對象+Proxy, ref其實也能夠用reactive實現,不過ref只用到了valute屬性,因此徹底可使用get和set來實現依賴收集和通知,有更好的性能java

function createRef(rawValue: unknown, shallow = false) {
  if (isRef(rawValue)) {
    return rawValue
  }
  let value = shallow ? rawValue : convert(rawValue)
  const r = {
    __v_isRef: true,
    get value() {
      track(r, TrackOpTypes.GET, 'value')
      return value
    },
    set value(newVal) {
      if (hasChanged(toRaw(newVal), rawValue)) {
        rawValue = newVal
        value = shallow ? newVal : convert(newVal)
        trigger(
          r,
          TriggerOpTypes.SET,
          'value',
          __DEV__ ? { newValue: newVal } : void 0
        )
      }
    }
  }
  return r
}
複製代碼

Proxy

effect其實並不會在咱們每次全部的reactive對象發生變化的時候都執行。 他是會只有在這個counter.num有變化的時候纔會執行一次。 因此這樣實際上是用了一個比較巧妙的辦法去監聽了變化 而後這個背後就是用proxy去作,並且若是數據是深層嵌套的,Proxy只會在獲取數據的時候,纔回去遞歸的用proxy,而不是vue2的首次渲染就所有定義好,這也是Vue3性能提高的一個緣由react

if (isObject(res)) {
      // Convert returned value into a proxy as well. we do the isObject check
      // here to avoid invalid value warning. Also need to lazy access readonly
      // and reactive here to avoid circular dependency.
      return isReadonly ? readonly(res) : reactive(res)
    }

複製代碼

響應式 && LocalStorage

咱們設計一個drag的小方塊,邏輯很簡單,就是能夠把div拖着亂跑,可是每次刷新, 小方塊會回到初始狀態,咱們若是想加入一個數據同步到localStorage的例子,用reactive和effect就能夠實現一個基本無注入的同步函數git

import {reactive, ref, effect} from "@vue/reactivity";

export default function LocalStorage(key, defaultValue){
    let data = reactive({});

    Object.assign(data, localStorage[key] && JSON.parse(localStorage[key]) || defaultValue);

    effect(() => localStorage[key] = JSON.stringify(data));

    return data;
}


複製代碼
export default {
    data: () => ({
        pos: LocalStorage("pos", {x:20, y:20})
    }),
}
複製代碼

只在data這裏加了一個函數設置了key,就能夠實現data數據和localStorage的同步了,有了這個腦洞,咱們其實能夠作不少事github

  1. 響應式 && 數據獲取 (ajax)
  2. console.log && info && error實現日誌文件寫入
  3. 響應式系統獨立,能夠用在任意框架離,好比react中

Option Vs Composition

這個沒啥多說得了,社區對比的文章也不少了,主要就是能夠把生命週期,響應式數據,操做函數,所有抽離再一個內部函數,因此vue3的組件就能夠無限的拆分,而且數據來源還能夠異常清晰ajax

好比咱們的todoMvc加一個功能,滾動一段距離後,上面的輸入框就fixed再頂部,用composition api就能夠把這個功能完整的抽離vuex

import { ref, onMounted, onUnmounted } from 'vue'
export default function useScroll() {
  const top = ref(0)

  function update(e) {
    top.value = window.scrollY
  }

  onMounted(() => {
    window.addEventListener('scroll', update)
  })

  onUnmounted(() => {
    window.removeEventListener('scroll', update)
  })

  return { top }
}

複製代碼

模板中直接使用

const {x,y} = useMouse()

複製代碼
<header class="header" :class="{fixed:top>130}">
複製代碼

可維護性直線提高,而且還能夠有效的把一個功能相關的數據都放在一塊兒,避免了vue2代碼維護的上下反覆橫條,官方經典的圖以下

一個顏色是一個功能,能夠看出vue3的代碼組織更爲合理

可是vue2的option api也不是徹底放棄,由於option的配置,更符合人的心智模型,啥玩意都是this.x 因此小程序option很合適,大型程序composition更利於組織和調試

還能夠直接看下官方吐槽的代碼

吐槽的官方Option組件

優化以後的composition版本 優雅程度直線上升

export default {
  setup () {
    // Network
    const { networkState } = useNetworkState()
    // Folder
    const { folders, currentFolderData } = useCurrentFolderData(networkState)
    const folderNavigation = useFolderNavigation({ networkState, currentFolderData })
    const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData)
    const { showHiddenFolders } = useHiddenFolders()
    const createFolder = useCreateFolder(folderNavigation.openFolder)
    // Current working directory
    resetCwdOnLeave()
    const { updateOnCwdChanged } = useCwdUtils()
    // Utils
    const { slicePath } = usePathUtils()
    return {
      networkState,
      folders,
      currentFolderData,
      folderNavigation,
      favoriteFolders,
      toggleFavorite,
      showHiddenFolders,
      createFolder,
      updateOnCwdChanged,
      slicePath
    }
  }
}

複製代碼

代碼和總結

代碼

語雀連載《Vue3生態技術內幕》

vue3的composition和React Hooks只是長的同樣,內部實現機制徹底不一樣,能夠算是雷鋒和雷峯塔的區別,Hooks每次render都會執行一次,composition 是隻調用一次, reactivity獨立後,讓vue3插上了想象力的翅膀,你對新的composition有什麼疑問,歡迎寫在留言區一塊兒討論

預告

  • 用戶答疑+八卦
  • reactivity和vuex的關係
  • class based api被幹掉的心路歷程
  • vue3設計的過程
  • 小右如何學習的

第二期嘉賓是周愛民老師,會深刻聊js,歡迎關注,持續更新

相關文章
相關標籤/搜索