You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nuxt3中创建SSR安全的唯一ID生成组合式函数遇重复ID问题

问题:创建SSR安全的全局递增ID组合式函数

问题描述

需要实现一个组合式函数,每次调用时递增全局计数器并返回唯一值,同时保证SSR安全(服务端渲染的ID与客户端hydrate时完全一致)。

现有代码:

// composables/useId.ts
let id = 0

export default function () {
    if (id >= Number.MAX_SAFE_INTEGER) id = Number.MIN_SAFE_INTEGER
    const incrementedId = id++
    return useState(() => incrementedId)
}

使用示例:

<ul>
    <li v-for="_ in 10">
        ID is: {{ useId() }}
    </li>
</ul>

问题现象:所有元素的ID值完全相同,原因是useState默认基于调用位置生成key,多次调用复用同一状态,导致返回值一致。

核心需求:保证HTML ID唯一性,例如在循环渲染组件时,每个组件实例的label与input能正确绑定:

// 父组件
<template>
    <MyInput v-for="_ in 10" />
</template>

// MyInput.vue
<template>
    <label :for="generatedId">Something</label>
    <input type="text" :id="generatedId">
</template>

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

解决方案

问题根源分析

  1. 原代码中useState无自定义key,多次调用会复用同一状态,导致ID重复。
  2. 全局变量id在服务端会被多个请求共享,引发跨请求ID冲突。

修正后的实现

借助Nuxt的useState实现请求级隔离的计数器,同时保证SSR状态同步:

// composables/useId.ts
export default function useId(prefix = 'id') {
  // 用全局共享的useState维护计数器,服务端每个请求独立初始化,客户端继承服务端状态
  const counter = useState('__unique_id_counter__', () => 0)

  // 先获取当前值再递增,确保ID序列连续唯一
  const currentId = counter.value
  counter.value += 1

  // 处理计数器溢出,重置到安全整数范围
  if (counter.value >= Number.MAX_SAFE_INTEGER) {
    counter.value = Number.MIN_SAFE_INTEGER
  }

  // 返回符合HTML规范的字符串ID(前缀+数字)
  return `${prefix}-${currentId}`
}

使用说明

  • 在组件中直接调用即可获得唯一ID:
    <script lang="ts" setup>
    const generatedId = useId()
    // 或自定义前缀
    const inputId = useId('user-input')
    </script>
    
  • 循环场景下,每个调用会返回递增的唯一ID,完全满足需求。

为什么可行

  • useState('__unique_id_counter__')在服务端为每个请求创建独立计数器,避免跨请求ID冲突;客户端会复用服务端序列化后的状态,保证SSR前后ID一致。
  • 每次调用递增计数器,确保ID全局唯一。
  • 返回带前缀的字符串ID,符合HTML ID命名规范(不能以数字开头)。

内容的提问来源于stack exchange,提问作者Matej

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 18:43:23