- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
React在很早之前的版本中加了useId,用于生成唯一ID。在Vue3.5版本中,终于也有了期待已久的useId。这篇文章来带你搞清楚useId有哪些应用场景,以及他是如何实现的.
关注公众号:【前端欧阳】,给自己一个进阶vue的机会 。
他的作用也是生成唯一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中打印的id0、id1和子组件UseIdChild2中打印的id0、id1是不是一样的呢?
答案是:不一样.
UseIdChild1中打印的id0的值为v-0,id1的值为v-1.
UseIdChild2中打印的id0的值为v-2,id1的值为v-3.
通过上面的这两个例子,我想你应该猜出来useId函数生成唯一ID的规律:“字符串v-加上自增的数字”.
其中的前缀v可以通过app.config.idPrefix进行自定义.
有的时候我们要渲染一个列表数据,需要列表的每一个item中有一个唯一的id,此时我们就可以使用useId去给每个item生成唯一的id.
这个是最简单的使用场景,接下来我们看看在服务端渲染(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>
上面的代码如果是跑在客户端渲染时没有任何问题,但是如果在服务端渲染时就会有警告了。如下图:
上面的警告意思是,在服务端时生成的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的源码,非常简单!!简化后的代码如下:
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,如下图:
从上图中可以看到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实例的源码如下图:
从上图中可以看到当没有父组件时,也就是最顶层的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.
最后此篇关于React的useId,现在Vue3.5终于也有了!的文章就讲到这里了,如果你想了解更多关于React的useId,现在Vue3.5终于也有了!的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
问题是,当用户回复彼此的帖子时,我必须这样做: margin-left:40px; 对于 1 级深度 react margin-left:80px; 对于 2 层深等 但是我想让 react div
我试图弄清楚如何将 React Router 与 React VR 连接起来。 首先,我应该使用 react-router dom/native ?目前尚不清楚,因为 React VR 构建在 Rea
我是 React 或一般编码背景的新手。我不确定这些陈述之间有什么区别 import * as react from 'react' 和 import react from 'react' 提前致谢!
我正在使用最新的稳定版本的 react、react-native、react-test-renderer、react-dom。 然而,react-native 依赖于 react@16.0.0-alp
是否 react 原生 应用程序开发可以通过软件架构实现,例如 MVC、MVP、MVVM ? 谢谢你。 最佳答案 是的。 React Native 只是你提到的那些软件设计模式中的“V”。如果你考虑其
您好我正在尝试在我的导航器右按钮中绑定(bind)一个功能, 但它给出了错误。 这是我的代码: import React, { Component } from 'react'; import Ico
我使用react native创建了一个应用程序,我正在尝试生成apk。在http://facebook.github.io/react-native/docs/signed-apk-android.
1 [我尝试将分页的 z-index 更改为 0,但没有成功] 这是我的codesandbox的链接:请检查最后一个选择下拉列表,它位于分页后面。 https://codesandbox.io/s/j
我注意到 React 可以这样导入: import * as React from 'react'; ...或者像这样: import React from 'react'; 第一个导入 react
我是 react-native 的新手。我正在使用 React Native Paper 为所有屏幕提供主题。我也在使用 react 导航堆栈导航器和抽屉导航器。首先,对于导航,论文主题在导航组件中不
我有一个使用 Ignite CLI 创建的 React Native 应用程序.我正在尝试将 TabNavigator 与 React Navigation 结合使用,但我似乎无法弄清楚如何将数据从一
我正在尝试在我的 React 应用程序中进行快照测试。我已经在使用 react-testing-library 进行一般的单元测试。然而,对于快照测试,我在网上看到了不同的方法,要么使用 react-
我正在使用 react-native 构建跨平台 native 应用程序,并使用 react-navigation 在屏幕之间导航和使用 redux 管理导航状态。当我嵌套导航器时会出现问题。 例如,
由于分页和 React Native Navigation,我面临着一种复杂的问题。 单击具有类别列表的抽屉,它们都将转到屏幕 问题陈述: 当我随机点击类别时,一切正常。但是,在分页过程中遇到问题。假
这是我的抽屉导航: const DashboardStack = StackNavigator({ Dashboard: { screen: Dashboard
尝试构建 react-native android 应用程序但出现以下错误 info Running jetifier to migrate libraries to AndroidX. You ca
我目前正在一个应用程序中实现 React Router v.4,我也在其中使用 Webpack 进行捆绑。在我的 webpack 配置中,我将 React、ReactDOM 和 React-route
我正在使用 React.children 渲染一些带有 react router 的子路由(对于某个主路由下的所有子路由。 这对我来说一直很好,但是我之前正在解构传递给 children 的 Prop
当我运行 React 应用程序时,它显示 export 'React'(导入为 'React')在 'react' 中找不到。所有页面错误 see image here . 最佳答案 根据图像中的错误
当我使用这个例子在我的应用程序上实现 Image-slider 时,我遇到了这个错误。 import React,{Component} from 'react' import {View,T
我是一名优秀的程序员,十分优秀!