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

Vue3組件渲染前的初始化過程

 更新時間:2024年07月02日 08:50:31   作者:F_Director  
Vue3?中一個組件從創(chuàng)建到掛在,會經(jīng)過3個重點步驟:創(chuàng)建組件實例,設(shè)置組件實例,創(chuàng)建并執(zhí)行帶副作用的渲染函數(shù),本文將著重講清?創(chuàng)建組件實例、設(shè)置組件實例?這兩個過程都做了什么,這部分邏輯很簡單,但你會從中學(xué)習(xí)到?Vue?優(yōu)秀的實踐技巧,需要的朋友可以參考下

Vue3 中一個組件從創(chuàng)建到掛在,會經(jīng)過3個重點步驟:

  • 創(chuàng)建組件實例
  • 設(shè)置組件實例
  • 創(chuàng)建并執(zhí)行帶副作用的渲染函數(shù)(render Effect)

本文將著重講清 創(chuàng)建組件實例、設(shè)置組件實例 這兩個過程都做了什么。這部分邏輯很簡單,但你會從中學(xué)習(xí)到 Vue 優(yōu)秀的實踐技巧。

一. 創(chuàng)建組件實例

這一步其實沒太多可說的,只是實例化了一個初始狀態(tài)的組件對象,并沒有什么邏輯在里面,不過你千萬別被這么龐大的信息量嚇到,我們關(guān)注的是組件實例上有哪些常見的屬性和方法,以及他們的維護(hù)方式。這能讓我們對Vue組件信息有更多的了解。

下面是copy的源碼:

function createComponentInstance (vnode, parent, suspense) {
  // 繼承父組件實例上的 appContext,如果是根組件,則直接從根 vnode 中取。
  const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext;
  const instance = {
    // 組件唯一 id
    uid: uid++,
    // 組件 vnode
    vnode,
    // 父組件實例
    parent,
    // app 上下文
    appContext,
    // vnode 節(jié)點類型
    type: vnode.type,
    // 根組件實例
    root: null,
    // 新的組件 vnode
    next: null,
    // 子節(jié)點 vnode
    subTree: null,
    // 帶副作用更新函數(shù)
    update: null,
    // 渲染函數(shù)
    render: null,
    // 渲染上下文代理
    proxy: null,
    // 帶有 with 區(qū)塊的渲染上下文代理
    withProxy: null,
    // 響應(yīng)式相關(guān)對象
    effects: null,
    // 依賴注入相關(guān)
    provides: parent ? parent.provides : Object.create(appContext.provides),
    // 渲染代理的屬性訪問緩存
    accessCache: null,
    // 渲染緩存
    renderCache: [],
    // 渲染上下文
    ctx: EMPTY_OBJ,
    // data 數(shù)據(jù)
    data: EMPTY_OBJ,
    // props 數(shù)據(jù)
    props: EMPTY_OBJ,
    // 普通屬性
    attrs: EMPTY_OBJ,
    // 插槽相關(guān)
    slots: EMPTY_OBJ,
    // 組件或者 DOM 的 ref 引用
    refs: EMPTY_OBJ,
    // setup 函數(shù)返回的響應(yīng)式結(jié)果
    setupState: EMPTY_OBJ,
    // setup 函數(shù)上下文數(shù)據(jù)
    setupContext: null,
    // 注冊的組件
    components: Object.create(appContext.components),
    // 注冊的指令
    directives: Object.create(appContext.directives),
    // suspense 相關(guān)
    suspense,
    // suspense 異步依賴
    asyncDep: null,
    // suspense 異步依賴是否都已處理
    asyncResolved: false,
    // 是否掛載
    isMounted: false,
    // 是否卸載
    isUnmounted: false,
    // 是否激活
    isDeactivated: false,
    // 生命周期,before create
    bc: null,
    // 生命周期,created
    c: null,
    // 生命周期,before mount
    bm: null,
    // 生命周期,mounted
    m: null,
    // 生命周期,before update
    bu: null,
    // 生命周期,updated
    u: null,
    // 生命周期,unmounted
    um: null,
    // 生命周期,before unmount
    bum: null,
    // 生命周期, deactivated
    da: null,
    // 生命周期 activated
    a: null,
    // 生命周期 render triggered
    rtg: null,
    // 生命周期 render tracked
    rtc: null,
    // 生命周期 error captured
    ec: null,
    // 派發(fā)事件方法
    emit: null
  }
  // 初始化渲染上下文
  instance.ctx = { _: instance }
  // 初始化根組件指針
  instance.root = parent ? parent.root : instance
  // 初始化派發(fā)事件方法
  instance.emit = emit.bind(null, instance)
  return instance
}

二. 設(shè)置組件實例

這一步的重點在創(chuàng)建上下文代理,和執(zhí)行處理setup函數(shù)的返回結(jié)果。

設(shè)置組件實例解決的問題,實際上都是組件渲染前所必須準(zhǔn)備好的內(nèi)容:

二.1 創(chuàng)建上下文代理

為什么需要上下文代理?可以舉一個簡單的例子:

<template>
  <p>{{ msg }}</p>
</template>
<script>
export default {
  data() {
    msg: 1
  }
}
</script>

為了方便維護(hù),Vue 把組件中不同狀態(tài)的數(shù)據(jù)存儲到組件實例(instance)的不同的屬性中,比如存儲到 setupState、ctx、data、props 中。比如,msg 就被收攏到 instance.data中。

可是在模板渲染時,渲染邏輯不知道 msg 是來自 data 還是 props 亦或者是 setupState。供給用戶的邏輯(比如, getCurrentInstance() api能在setup中訪問到組件實例的變量和屬性,但不推薦使用此api) 在訪問 msg 時候也需要預(yù)先判斷 msg 的溯源,然后才能決定是通過 instance.data 訪問還是 instance.props 訪問。這無疑增加了變量查詢的負(fù)擔(dān)。

為了方便使用,Vue 會直接訪問渲染上下文 instance.ctx 中的屬性,對instance.ctx做一層 proxy,對渲染上下文 instance.ctx 屬性的訪問和修改,代理到對 setupState、ctx、data、props 中的數(shù)據(jù)的訪問和修改。

你需要學(xué)習(xí)的是訪問組件變量時對數(shù)據(jù)集合的訪問順序,以及accessKey這樣的柯里化思想。

值得注意的是,在set時,如果直接對props中的數(shù)據(jù)賦值,在非生產(chǎn)環(huán)境中就會產(chǎn)生一條警告。

創(chuàng)建accessKey的好處是節(jié)約了對不同上下文對象進(jìn)行反復(fù)hasOwnPropety的性能損耗。

二.2 判斷處理setup函數(shù)

這一步主要就是給setup注入?yún)?shù),然后包了一層try...catch。然后處理setup的返回值。

為什么要包 try...catch?

筆者認(rèn)為,setup 函數(shù)畢竟還是用戶自己寫的,難免出現(xiàn)邏輯錯誤,用 try...catch 不僅能防止程序被終止還能獲取錯誤信息被Vue攔截處理。這是一種良好實踐,在我們?nèi)粘i_發(fā)中,也應(yīng)該考慮將暴露給用戶書寫的邏輯區(qū)域包一層try...catch來捕獲不屬于框架之內(nèi)的錯誤。

二.3 完成組件實例設(shè)置

這一塊就是在處理完setup返回結(jié)果后進(jìn)行的,因為組件可能缺失render函數(shù),用戶的常用寫法是template模板,且用戶的編譯環(huán)境可能并非是運行時編譯(runtime-compiler)版本。所以這里需要統(tǒng)一轉(zhuǎn)換為render函數(shù)的形式,以方便后面instance.update中方便拿到subTree。

這部分邏輯用一個腦圖就能闡明:

以上就是Vue3組件渲染前的初始化過程的詳細(xì)內(nèi)容,更多關(guān)于Vue3組件初始化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論