vuejs / rfcs

RFCs for substantial changes / feature additions to Vue core
4.85k stars 549 forks source link

Can vue provide `useId` hook #556

Closed RhysXia closed 10 months ago

RhysXia commented 2 years ago

What problem does this feature solve?

In the SSR environment, sometimes it is necessary to create a stable id that is the same on the server and the client.

For example, a server request wants to put the requested data in html (for example window.SSR_DATA={//data}), and then the client obtains and uses the data through a specific key from SSR_DATA.

We can encapsulate this method into a hook, for example called useServerData.

useServerData may be used multiple times by the same component, or it may be used by multiple components. Therefore, this key is required to be globally unique and the same in the same place on the server and client.

We can also guarantee uniqueness by passing the key to useServerData. But this is very inelegant and there is no way to guarantee that it will be unique. For example, useServerData is used in multiple components, so we need to go to each component code to confirm whether there is any duplication.In fact, this key does not need to be concerned about the component at all.

So can vue provide a way to generate id staying stable and unique between server and client?

A similar hook is provided in react18, you can refer to.

What does the proposed API look like?

const id1 = useId();
const id2 = useId(); // id1 !== id2
danielroe commented 2 years ago

I've released a tiny directive that may help: vue-bind-once. Sample usage:

<div v-bind-once="{ id: Math.random() }" />

This will work on both server and on client re-hydration.

RhysXia commented 2 years ago

@danielroe Is this method only available for binding on elements? I want this id to be available everywhere,like hooks.

jshimkoski commented 2 years ago

Another option (not as flexible as vue-bind-once but inspired by it) is: vue-uid

It generates an SSR-friendly unique identifier that is automatically assigned to the id on the element.

Sample usage:

<script setup lang="ts">
import { ref } from 'vue'
const input = ref<null | HTMLElement>(null)
</script>

<template>
  <div>
    <label :for="input?.id">Input label</label>
    <input v-uid ref="input" type="text">
  </div>
</template>

Both vue-bind-once and vue-uid are only available when bound to elements as they are directives. Both use getSSRProps() as documented here: https://vuejs.org/guide/scaling-up/ssr.html#custom-directives

LeBenLeBen commented 2 years ago

In case you’re looking for a composable, I came up with that solution: https://github.com/liip/chusho/blob/main/packages/chusho/lib/composables/useCachedUid.ts#L20-L41

simonmaass commented 1 year ago

is there any idea for vue2?

wobsoriano commented 1 year ago

@LeBenLeBen I see different values for client and server when I use that composable in Nuxt