首页 > 其他分享 >React的useId,现在Vue3.5终于也有了!

React的useId,现在Vue3.5终于也有了!

时间:2024-09-24 08:50:05浏览次数:7  
标签:vue ids 生成 React Vue3.5 组件 服务端 useId

前言

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。

标签:vue,ids,生成,React,Vue3.5,组件,服务端,useId
From: https://www.cnblogs.com/heavenYJJ/p/18428164

相关文章

  • react native的notifee消息
       reactnative上的notifee组建可发送localnotification和remotepushnotification,可订阅各种Event。我使用的是localnotification。另一个与之对应的是exponotification,也是很好的组建,但我的app未来想用bare类型,脱离expo,所以优先选择notifee。官方文档:https://notife......
  • React hooks子组件暴露方法示例
    说明通常情况下,React 子组件使用父组件的方法或值通过props传递,反过来,父组件如果需要子组件的方法就需要子组件将自己的方法暴露出去。以下是一个实例:User.tsximportReact,{FC,useEffect,useState,useRef}from'react';import{Button,Table}from'antd';impor......
  • 【艾思科蓝】前端框架巅峰对决:React、Vue与Angular的全面解析与实战指南
    【JPCS独立出版】​第三届能源与动力工程国际学术会议(EPE2024)_艾思科蓝_学术一站式服务平台更多学术会议请看:https://ais.cn/u/nuyAF3 引言在快速发展的前端技术领域,选择合适的框架或库对于项目的成功至关重要。React、Vue和Angular作为当前最流行的三大前端框架/库,各自......
  • 学习如何:useEFFECT 和 useSTATE,一个 REACT 应用程序
    我一直在开发一个名为“Heat”的网络应用程序,该应用程序的唯一目的是帮助我学习和应用JavaScript并改进我的CSS,还有很多后端。我们的计划是创建一个具有视觉吸引力的网络应用程序,并具有一些有趣的功能。在这个过程中我学到了什么:前端是使用reactjs构建的,我选择react只是出于好......
  • 如何在Reactjs中制作动态进度条
    使用react和循环进度组件构建性能仪表板在本博客中,我们将探讨如何使用react构建性能指标仪表板。仪表板显示不同绩效指标(例如可访问性、seo和最佳实践)的循环进度指示器。进度指示器逐渐填满,模拟加载动画。该项目使用tailwindcss进行样式设计,并组合了多个组件来创建灵活且......
  • 如何使用 useTransition hook 提高 React 性能
    react是一个用于构建用户界面的流行javascript库。它以高效且专注于创建可重用的ui组件而闻名。react的关键特性之一是引入了钩子,它是挂钩到react状态的函数。这些钩子中的一个是usetransition钩子。该钩子允许在不阻塞界面的情况下进行状态更改,从而带来流畅的体验。......
  • 如何在 React 中使用上下文
    欢迎回来,朋友们!?今天我们将回顾名为usecontext的reacthook的基础知识。usecontext是一个强大的工具,它比usestate更进一步,创建了一个类似全局的state,可以将信息传递给子组件和孙组件,而无需直接传递props。?但我有点超前了。?如果你不熟悉usestate,请先跳过去阅读我之前......
  • 如何在 ReactJS 中创建可重用的 Button 组件
    按钮无疑是任何react应用程序中重要的ui组件,按钮可能用于提交表单或打开新页面等场景。您可以在react.js中构建可重用的按钮组件,您可以在应用程序的不同部分中使用它们。因此,维护您的应用程序将变得更加简单,并且您的代码将保持dry(不要重复)。您必须首先在组件文件夹中创建一......
  • 如何使您的 React 应用程序更快:性能提示和最佳实践
    啊,反应!我们喜爱的用于构建ui的库。它就像一剂神奇的药剂,让我们的网络应用程序感觉具有交互性和快速性——直到有一天,它却没有了。突然,你注意到事情变慢了。点击按钮就像用信鸽寄信一样。您的应用程序从快如闪电变成了慢吞吞,用户开始给您“看”。不过别担心!就像咖啡可以解决大部......
  • 如何使用 AWS 部署带有自定义域的 React 项目?
    使用aws(amazonwebservices)等云提供商通过自定义域部署react应用程序可能看起来令人畏惧,但当分解为可管理的步骤时,它就很简单。在本文中,我们将指导您完成从构建应用程序到使其在您的自定义域上运行的整个过程。当您准备好与世界分享您的react项目时,使用自定义域部署它可以为......