· Zen HuiFer · Learn  · 7 min read

React's useId, now Vue3.5 finally has it!

Vue 3.5 introduces useId, a utility similar to React's for generating unique IDs. Essential for accessibility and server-side rendering consistency, useId helps avoid warnings and ensures unique element identifiers across the app.

Vue 3.5 introduces useId, a utility similar to React's for generating unique IDs. Essential for accessibility and server-side rendering consistency, useId helps avoid warnings and ensures unique element identifiers across the app.

React’s useId, now Vue3.5 finally has it!

preface

React was added in earlier versionsuseIdUsed to generate a unique ID. In Vue 3.5 version, there is finally the long-awaiteduseId. This article will help you clarifyuseIdWhat are the application scenarios and how is it implemented.

The role of useId

His function is also to generate a unique ID, which is called every time within the same Vue applicationuseIdThe generated IDs are all different.

The usage method is also very simple, the code is as follows:

<script setup lang="ts">
import { useId } from 'vue'const id0 = useId();
console.log(id0); // v-0const id1 = useId();
console.log(id1); // v-1const id2 = useId();
console.log(id2); // v-2
</script>

Some friends may have problems seeing this. The examples above are all called within the same componentuseId. If I call them separately in different componentsuseIdAre the IDs generated by these components still unique?

For example, in the following example, the parent component code is as follows:

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

SubcomponentsUseIdChild1The code is as follows:

<script setup lang="ts">
import { useId } from "vue";const id0 = useId();
const id1 = useId();console.log(id0);
console.log(id1);
</script>

SubcomponentsUseIdChild2The code is as follows:

<script setup lang="ts">
import { useId } from "vue";const id0 = useId();
const id1 = useId();console.log(id0);
console.log(id1);
</script>

From the above code, you can see that the code inside the two sub components is actually the same. Can you guess what the sub components areUseIdChild1Printed in the middleid0id1And sub componentsUseIdChild2Printed in the middleid0id1Is it the same?

The answer is: dissimilarity

UseIdChild1Printed in the middleid0The value isv-0id1The value isv-1

UseIdChild2Printed in the middleid0The value isv-2id1The value isv-3

Based on the above two examples, I think you should guessuseIdThe rule of generating unique IDs for functions: “Stringv-add Self increasing numbers ”。

The prefix in itvCan be done throughapp.config.idPrefixCustomize.

Sometimes when we need to render a list of data, we need each item in the list to have a unique ID. In this case, we can useuseIdGenerate a unique ID for each item.

This is the simplest usage scenario. Next, let’s take a look at server-side rendering (SSR)useIdThe usage scenario.

Using useId in server-side rendering (SSR)

Firstly, we need to identify the pain points during server-side rendering?

Let’s take a look at an example of server-side rendering. The code is as follows:

<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>

If the above code runs on the client-side rendering, there will be no problem, but if it runs on the server-side rendering, there will be a warning. As shown in the following figure:

The warning above means that the value of the ID generated on the server is0.4050816845323888. But the value of the ID generated on the client side is0.4746900241123273The ID values generated these two times are different, which is why the warning appears.

Some friends may wonder why the ID is generated again on the client after being generated on the server?

To answer the above question, let’s first understand the process of server-side rendering (SSR):

  • Firstly, an interface request will be initiated on the server (Node.js environment) to retrieve the data required for page rendering from the backend.

  • Generate an HTML string for the page based on the received data, and at this point, an ID will be generated on the server. This step is calleddehydrate(Dehydration).

  • Send the HTML string generated by the server to the client (browser).

  • The browser can use the HTML string generated by the server as the first screen content and directly render it onto the page. But at this point, events such as click have not yet been bound to the DOM, so they need to be rendered again on the client side. Will generate the ID again on the client side, this step is calledhydrate(Water injection).

Since we are usingMath.random()Generate the ID and execute it on both the server and client every timeMath.random()The generated ID value is naturally different, which is why the warning above appears.

Got ituseIdAfter that, resolving the warning above is very simple, just put it in placeMath.random()Change touseId()That’s enough. The code is as follows:

<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>

becauseuseIdGenerated during server-side renderingv-0Still rendering on the client sidev-0

Some friends may have questions, which were not mentioned earlieruseIdEach execution will give the following numbers+1. So, after executing once on the server, should the generated ID be different when executing again on the client??

useIdThe generated ‘auto increment part’ is maintained on the Vue instanceidsIn terms of properties, a Vue instance will be generated on the Node.js side during server-side rendering. But when the client renders, a new Vue instance will be generated in the browser, and at this timeidsThe attributes will also be reset, so they will be executed on both the server and client sidesuseIdThe generated values are the same.

How is useId implemented

Let’s take a lookuseIdThe source code is very simple!! The simplified code is as follows:

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

thisgetCurrentInstanceI think many students are familiar with the function, which returns the current Vue instance.

touseIdMake a breakpoint to take a look at the current Vue instancei, as shown in the following figure:

From the above figure, it can be seen that on the Vue instanceidsA property is an array, where the first item is an empty string, the second item is the number 0, and the third item is also the number 0

Let’s take another lookuseIdHow to return a unique ID, as follows:

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

The generated unique ID consists of three parts:

  • The first part is the prefix, fromapp.config.idPrefixTaken from the middle. If there is no configuration, then it is just a stringv

  • The second part is to write a dead string-

  • The third part isi.ids[0] + i.ids[1]++Among themids[0] The value is an empty string.i.ids[1]++Here, the value is taken first, and then executed++So the value of the third part is a number0. Call againuseIdWhen, due to the previous execution++That’s it. The current numerical value is1And execute it again++

Some of the buddies here have questions again. It looks likeidsThe attribute exists on the Vue instance. Each Vue component has a Vue instance, so each component has its own maintenanceidsAttributes. In the example you mentioned earlierUseIdChild1Subcomponents andUseIdChild2Generated by each sub componentid0The value should be the samev-0Well, why is onev-0The other one isv-2What about it?

The answer is actually quite simple, on all Vue instancesidsThe attributes are all the same array, pointing to the one above the top-level component instanceidsAttributes. The source code for creating a Vue instance is shown in the following figure:

From the above figure, it can be seen that when there is no parent component, which is the top-level Vue component instance, it will beidsSet attribute as array['', 0, 0]

When generating Vue instances of child components, due to the presence ofidsAttribute, so we used the one above the parent component. The pointers all point to the top-level Vue instanceidsThat’s why all Vue component instances have attributesidsAll attributes point to the same array.

That’s whyUseIdChild1Subcomponents andUseIdChild2Generated by each sub componentid0The value of one isv-0The other one isv-2

summary

New additions to Vue 3.5useIdWe can generate unique IDs within Vue applications, and we can use themuseIdGenerate a unique ID for each item in the list data.

And in the server-side rendering (SSR) scene, both the server-side and client-side executeuseIdThe generated ID is the same. We can use this feature touseIdResolve warnings caused by inconsistent IDs generated by the server-side and client-side in SSR applications.

Finally, we talked aboutuseIdThe implementation is also very simple, and the generated ID is divided into three parts:

  • The first part is the prefix:app.config.idPrefixIf there is no configuration, then it is just a stringv

  • Part 2 String:-

  • The value of the third part is a self increasing number that exists on the Vue instanceidsAttributes, on all Vue instancesidsAll attributes point to the same array. That’s why it’s saiduseIdCan be in Vue in app Generate a unique ID instead of Within Vue components Generate a unique ID.

Back to Blog

Related Posts

View All Posts »
New package in Go 1.23: unique

New package in Go 1.23: unique

Go 1.23 introduces unique package for value normalization, enhancing memory efficiency and equality checks. Learn how "interning" works with unique and its benefits for Go developers.

How to cache well in Go

How to cache well in Go

Optimize Go app performance with caching strategies. Learn local vs distributed cache, memory management, and eviction policies. Enhance efficiency with Go's new unique package.

The noCopy strategy you should know in Golang

The noCopy strategy you should know in Golang

Discover the importance of noCopy in Golang development. Learn how it prevents accidental copying of critical structures like sync primitives. Enhance your Go code safety and efficiency.