React的useId,現在Vue3.5終於也有了!

来源:https://www.cnblogs.com/heavenYJJ/p/18428164
-Advertisement-
Play Games

前言 React在很早之前的版本中加了useId,用於生成唯一ID。在Vue3.5版本中,終於也有了期待已久的useId。這篇文章來帶你搞清楚useId有哪些應用場景,以及他是如何實現的。 關註公眾號:【前端歐陽】,給自己一個進階vue的機會 useId的作用 他的作用也是生成唯一ID,同一個Vue ...


前言

React在很早之前的版本中加了useId,用於生成唯一ID。在Vue3.5版本中,終於也有了期待已久的useId。這篇文章來帶你搞清楚useId有哪些應用場景,以及他是如何實現的。

關註公眾號:【前端歐陽】,給自己一個進階vue的機會

useId的作用

他的作用也是生成唯一ID,同一個Vue應用裡面每次調用useId生成的ID都不同。

使用方法也很簡單,代碼如下:

<script setup lang="ts">
import { useId } from 'vue'

const id0 = useId();
console.log(id0); // v-0

const id1 = useId();
console.log(id1); // v-1

const id2 = useId();
console.log(id2); // v-2
</script>

看到這裡有的小伙伴會有問題,你上面的例子都是在同一組件裡面調用useId。那如果我在不同的組件裡面分別調用useId,這些組件生成的ID還是唯一的嗎?

比如下麵這個例子,父組件代碼如下:

<template>
  <div>
    <UseIdChild1 />
    <UseIdChild2 />
  </div>
</template>

子組件UseIdChild1代碼如下:

<script setup lang="ts">
import { useId } from "vue";

const id0 = useId();
const id1 = useId();

console.log(id0);
console.log(id1);
</script>

子組件UseIdChild2代碼如下:

<script setup lang="ts">
import { useId } from "vue";

const id0 = useId();
const id1 = useId();

console.log(id0);
console.log(id1);
</script>

從上面的代碼可以看到兩個子組件裡面的代碼實際是一樣的,那你猜猜子組件UseIdChild1中列印的id0id1和子組件UseIdChild2中列印的id0id1是不是一樣的呢?

答案是:不一樣

UseIdChild1中列印的id0的值為v-0id1的值為v-1

UseIdChild2中列印的id0的值為v-2id1的值為v-3

通過上面的這兩個例子,我想你應該猜出來useId函數生成唯一ID的規律:“字元串v-加上自增的數字”。

其中的首碼v可以通過app.config.idPrefix進行自定義。

有的時候我們要渲染一個列表數據,需要列表的每一個item中有一個唯一的id,此時我們就可以使用useId去給每個item生成唯一的id。

這個是最簡單的使用場景,接下來我們看看在服務端渲染(SSR)中useId的使用場景。

在服務端渲染(SSR)中使用useId

首先我們要搞清楚服務端渲染時有哪些痛點?

我們來看一個服務端渲染的例子,代碼如下:

<template>
  <div>
    <label :htmlFor="id">Do you like Vue3.5?</label>
    <input type="checkbox" name="vue3.5" :id="id" />
  </div>
</template>

<script setup lang="ts">
const id = Math.random();
</script>

上面的代碼如果是跑在客戶端渲染時沒有任何問題,但是如果在服務端渲染時就會有警告了。如下圖:
warn

上面的警告意思是,在服務端時生成的id的值為0.4050816845323888。但是在客戶端時生成的id的值卻是0.4746900241123273,這兩次生成的id值不同,所以才會出現警告。

可能有的小伙伴會有疑問,為什麼在服務端生成一次id後,在客戶端又去生成一次id呢?

為瞭解答上面這個問題,我們先來瞭解一下服務端渲染(SSR)的流程:

  • 首先會在服務端(Node.js環境)發起介面請求,從後端拿到頁面渲染需要的數據。

  • 根據拿到的數據去生成頁面的HTML字元串,此時就會在服務端生成一次id,這一步叫dehydrate(脫水)。

  • 將服務端生成的HTML字元串發送給客戶端(瀏覽器)。

  • 瀏覽器拿到了服務端生成的HTML字元串可以將其作為首屏內容,直接渲染到頁面上。但是此時click之類的事件還沒綁定在DOM上,所以在客戶端需要再渲染一次。就會在客戶端再次生成一次id,這一步叫hydrate(註水)。

由於我們這裡是使用Math.random()去生成的id,在服務端和客戶端每次執行Math.random()生成的id值當然就不同了,所以才會出現上面的警告。

有了useId後,解決上面的警告就很簡單了,只需要把Math.random()改成useId()就可以了。代碼如下:

<template>
  <div>
    <label :htmlFor="id">Do you like Vue3.5?</label>
    <input type="checkbox" name="vue3.5" :id="id" />
  </div>
</template>

<script setup lang="ts">
const id = useId();
</script>

因為useId在服務端渲染時會生成v-0,在客戶端渲染時依然還是v-0

可能有的小伙伴有疑問,前面不是講的useId每執行一次會給後面的數字+1。那麼服務端執行一次後,再去客戶端執行一次,講道理應該生成的ID不一樣吧??

useId生成的“自增數字部分”是維護在vue實例上面的ids屬性上,服務端渲染時會在Node.js端生成一個vue實例。但是客戶端渲染時又會在瀏覽器中重新生成一個新的vue實例,此時vue實例上的ids屬性也會被重置,所以在服務端和客戶端執行useId生成的值是一樣的。

useId是如何實現的

我們來看看useId的源碼,非常簡單!!簡化後的代碼如下:

function useId(): string {
  const i = getCurrentInstance()
  if (i) {
    return (i.appContext.config.idPrefix || 'v') + '-' + i.ids[0] + i.ids[1]++
  }
  return ''
}

這個getCurrentInstance函數我想很多同學都比較熟悉,他的作用是返回當前vue實例。

useId打個斷點,來看一下當前vue實例i,如下圖:
instance

從上圖中可以看到vue實例上的ids屬性是一個數組,數組的第一項是空字元串,第二項是數字0,第三項也是數字0

我們再來看看useId是如何返回唯一ID的,如下:

return (i.appContext.config.idPrefix || 'v') + '-' + i.ids[0] + i.ids[1]++

生成的唯一ID由三部分組成:

  • 第一部分為首碼,從app.config.idPrefix中取的。如果沒有配置,那麼就是字元串v

  • 第二部分為寫死的字元串-

  • 第三部分為i.ids[0] + i.ids[1]++,其中ids[0] 的值為空字元串。i.ids[1]++這裡是先取值,然後再執行++,所以第三部分的值為數字0。再次調用useId時,由於上一次執行過一次++了。此時的數字值為1,並且再次執行++

看到這裡有的小伙伴又有疑問了,這裡看上去ids屬性是存在vue實例上面的。每個vue組件都有一個vue實例,那麼每個組件都有各自維護的ids屬性。
那你前面的那個例子中UseIdChild1子組件和UseIdChild2子組件中各自生成的id0的值應該是一樣的v-0吧,為什麼一個是v-0,另外一個是v-2呢?

答案其實很簡單,所有vue實例上面的ids屬性都是同一個數組,指向的是頂層組件實例上面的那個ids屬性。創建vue實例的源碼如下圖:
source

從上圖中可以看到當沒有父組件時,也就是最頂層的vue組件實例,就將其ids屬性設置為數組['', 0, 0]

當生成子組件的vue實例時,由於父組件上面有ids屬性,所以就用父組件上面的了。指針都是指向的是最頂層vue實例上面的ids屬性,所以才會說所有的vue組件實例上面的ids屬性都是指向同一個數組。

這也就是為什麼UseIdChild1子組件和UseIdChild2子組件中各自生成的id0的值一個是v-0,另外一個是v-2

總結

Vue3.5新增的useId可以在Vue應用內生成唯一的ID,我們可以使用useId給列表數據中的每一個item生成一個唯一的id。

並且在服務端渲染(SSR)場景中,服務端和客戶端執行useId生成的是同一個ID。利用這個特點我們可以使用useId解決一些在 SSR 應用中,伺服器端和客戶端生成的 ID 不一致導致的警告。

最後我們講了useId的實現也很簡單,生成的ID分為三部分:

  • 第一部分為首碼:app.config.idPrefix,如果沒有配置,那麼就是字元串v

  • 第二部分字元串:-

  • 第三部分的值為一個自增的數字,存在vue實例上面的ids屬性,所有的vue實例上面的ids屬性都是指向同一個數組。這也就是為什麼說useId可以在Vue應用內生成唯一的ID,而不是在Vue組件內生成唯一的ID。

關註公眾號:【前端歐陽】,給自己一個進階vue的機會

另外歐陽寫了一本開源電子書vue3編譯原理揭秘,看完這本書可以讓你對vue編譯的認知有質的提升。這本書初、中級前端能看懂,完全免費,只求一個star。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • title: 深入理解 Nuxt.js 中的 app:error:cleared 鉤子 date: 2024/9/28 updated: 2024/9/28 author: cmdragon excerpt: Nuxt.js 中的 app:error:cleared 鉤子的用途及其實現方式。這個鉤子 ...
  • 我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 本文作者:修能 What's? 數棧產品里的 Descriptions 組件實際上就是 antd 的 Descriptions 組件,那麼 antd 的 Descrip ...
  • title: 深入理解 Nuxt.js 中的 app:error 鉤子 date: 2024/9/27 updated: 2024/9/27 author: cmdragon excerpt: 摘要:本文深入講解了Nuxt.js框架中的app:error鉤子,介紹其在處理web應用中致命錯誤的重要作 ...
  • title: 深入理解 Nuxt 中的 app created 鉤子 date: 2024/9/26 updated: 2024/9/26 author: cmdragon excerpt: 摘要:本文深入介紹了 Nuxt.js 中的 app:created 鉤子,包括其觸發時機、用途及使用方法。通 ...
  • 一、流水管線 實現邏輯: 1)先自定義幾個點,通過CatmullRomCurve3生成一條平滑曲線 2)根據生成的曲線在XY面擴展一個面,其中需要註意頂點索引、UV坐標添加的順序,否則可能會導致繪製的圖片混亂,不是完整的圖片 3)添加紋理同時設置偏移量實現流動效果 4)為了保證顯示的箭頭圖標不失真, ...
  • title: Nuxt Kit 實用工具的使用示例 date: 2024/9/25 updated: 2024/9/25 author: cmdragon excerpt: 摘要:本文介紹了Nuxt Kit工具在開發集成工具或插件時,如何訪問和修改Nuxt應用中使用的Vite或webpack配置,以 ...
  • 混淆指定js文件 fomartJs.bat @echo off REM 定義一個包含文件名的數組 set jsFiles=("polyfills.b4665eab.js" "manifest.b09f6bad.js" "index.f8bec5fb.js") REM 遍曆數組中的每個文件 for % ...
  • title: 使用 Nuxt Kit 的構建器 API 來擴展配置 date: 2024/9/24 updated: 2024/9/24 author: cmdragon excerpt: 摘要:本文詳細介紹瞭如何使用 Nuxt Kit 的構建器 API 來擴展和定製 Nuxt 3 項目的 webp ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...