如何在React中为表单标签生成唯一ID?

Art*_*gin 115 reactjs

我有labels的表单元素,我希望有唯一的ID来链接labels到具有htmlFor属性的元素.像这样的东西:

React.createClass({
    render() {
        const id = ???;
        return (
            <label htmlFor={id}>My label</label>
            <input id={id} type="text"/>
        );
    }
});
Run Code Online (Sandbox Code Playgroud)

我过去常常根据this._rootNodeIDReact 0.13 生成ID,但它不可用.现在最好和/或最简单的方法是什么?

t_d*_*m93 106

更新反应 18

React 18 引入了一个新的钩子,它生成一个唯一的 ID:

const id = useId();
Run Code Online (Sandbox Code Playgroud)

挂钩 API 文档: https: //react.dev/reference/react/useId

从您的示例中,您可以在组件内调用挂钩:

import React, { useId } from 'react'

function TextField = (props) => {
  // generate unique ID
  const id = useId(); 

  return (
    <>
      <label htmlFor={id}>My label</label>
      <input id={id} type="text"/>
    </>
  );
}
Run Code Online (Sandbox Code Playgroud)

  • **注意** - 正如 @iiiml0sto1 提到的, [`useId`](https://reactjs.org/docs/hooks-reference.html#useid) 创建由冒号包围的字符串(例如 `:r5:`),其中 ` querySelector` 不支持。[使用“querySelector”时必须转义冒号](/sf/answers/5262468221/)。[`useId` 钩子允许使用前缀](https://beta.reactjs.org/reference/react/useId#specifying-a-shared-prefix-for-all- generated-ids),但这只会在前面添加带有值的字符串,同时仍应用冒号。 (5认同)

Art*_*gin 80

这个解决方案适合我.

utils/newid.js:

let lastId = 0;

export default function(prefix='id') {
    lastId++;
    return `${prefix}${lastId}`;
}
Run Code Online (Sandbox Code Playgroud)

我可以像这样使用它:

import newId from '../utils/newid';

React.createClass({
    componentWillMount() {
        this.id = newId();
    },
    render() {
        return (
            <label htmlFor={this.id}>My label</label>
            <input id={this.id} type="text"/>
        );
    }
});
Run Code Online (Sandbox Code Playgroud)

但它不适用于同构应用程序.

新增17.08.2015.取而代之的定制NEWID函数可以使用UNIQUEID从lodash.

更新于2016年1月28日.最好在中生成ID componentWillMount.

  • 没有理由对我们大喊大叫. (8认同)
  • 不要在`render`中这样做!在`componentWillMount`中创建id (6认同)
  • 因为它将开始在浏览器中再次从1st生成ID.但实际上您可以在服务器和浏览器中使用不同的前缀. (3认同)
  • 我在构造函数中使用lodash中的uniqueId并使用setState来设置id.适用于我的客户端应用程序. (3认同)

sar*_*ink 61

id应该放在componentWillMount(更新为2018)内constructor,而不是render.将其放入render将不必要地重新生成新的ID.

如果你使用下划线或lodash,有一个uniqueId函数,所以你得到的代码应该是这样的:

constructor(props) {
    super(props);
    this.id = _.uniqueId("prefix-");
}

render() { 
  const id = this.id;
  return (
    <div>
        <input id={id} type="checkbox" />
        <label htmlFor={id}>label</label>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

  • 或者您也可以将它放入构造函数中. (10认同)
  • 由于您没有跟踪 id 的值,因此还可以使用 const {current: id} = useRef(_uniqueId('prefix-'))` (5认同)
  • 不要将状态用于不是由于给定组件的变化(不变)而引起的事物。从概念上讲是错误的。 (5认同)
  • 使用 useRef 而不是 use State 有什么区别? (4认同)
  • 任何人都可以建议如何使用 React 16.8 中的新 Hook 来完成这项工作? (2认同)

rpe*_*rce 13

从2019-04-04开始,这似乎可以通过React Hooks'完成useState

import React, { useState } from 'react'
import uniqueId from 'lodash/utility/uniqueId'

const Field = props => {
  const [ id ] = useState(uniqueId('myprefix-'))

  return (
    <div>
      <label htmlFor={id}>{props.label}</label>
      <input id={id} type="text"/>
    </div>
  )      
}

export default Field
Run Code Online (Sandbox Code Playgroud)

据我了解,您将忽略数组结构中的第二个数组项,该数组项将允许您更新id,现在您拥有的值将在组件的整个生命周期内都不会再次更新。

的值id将为myprefix-<n>其中<n>是从返回的增量整数值uniqueId。如果那还不够独特,请考虑制作自己喜欢的

function gen4() {
  return Math.random().toString(16).slice(-4)
}

function simpleUniqueId(prefix) {
  return (prefix || '').concat([
    gen4(),
    gen4(),
    gen4(),
    gen4(),
    gen4(),
    gen4(),
    gen4(),
    gen4()
  ].join(''))
}
Run Code Online (Sandbox Code Playgroud)

或查看我在此处发布的库:https : //github.com/rpearce/simple-uniqueid。还有成百上千的其他唯一ID东西,但是uniqueId带有前缀的lodash 足以完成任务。


更新2019-07-10

感谢@Huong Hk为我指出了钩子惰性初始状态,其总和是您可以将函数传递给useState钩子,该函数将仅在初始安装上运行。

// before
const [ id ] = useState(uniqueId('myprefix-'))

// after
const [ id ] = useState(() => uniqueId('myprefix-'))
Run Code Online (Sandbox Code Playgroud)

  • 最好提供一个函数作为`initialState`#1```const [id] = useState(()=&gt; uniqueId('myprefix-'))```而不是函数#2的结果[id] = useState(uniqueId('myprefix-'))```以上两种方式的状态:`id`相同。但是不同的是``uniqueId('myprefix-')```将执行一次(#1),而不是每次重新渲染(#2)。请参阅:惰性初始状态:https://reactjs.org/docs/hooks-reference.html#lazy-initial-state如何懒惰地创建昂贵的对象?:https://reactjs.org/docs/hooks-faq.html #how-to-to-create-expensive-objects lazyly (2认同)

Stu*_*ine 7

您可以使用诸如node-uuid 之类的库来确保您获得唯一的 ID。

安装使用:

npm install node-uuid --save

然后在你的反应组件中添加以下内容:

import {default as UUID} from "node-uuid";
import {default as React} from "react";

export default class MyComponent extends React.Component {   
  componentWillMount() {
    this.id = UUID.v4();
  }, 
  render() {
    return (
      <div>
        <label htmlFor={this.id}>My label</label>
        <input id={this.id} type="text"/>
      </div>
    );
  }   
}
Run Code Online (Sandbox Code Playgroud)

  • 不纯的 `render` 违反了 https://facebook.github.io/react/docs/component-specs.html (5认同)
  • 这在同构应用程序中不起作用,因为服务器上生成的 id 与客户端上生成的 id 不同。 (3认同)
  • 答案似乎已更新以符合规范 (2认同)
  • 但它被列为答案的一部分,这是非常具有误导性的 (2认同)
  • “ID 太独特”似乎是投反对票的任意理由。UUID 并不昂贵。 (2认同)

Tan*_*kom 6

扩展@foriall评论

如果整个目标是链接 a<label><input>元素并且它们不依赖于 props,那么最好和性能最好的方法是使用useRef.

useRef 返回一个可变的 ref 对象,其.current属性被初始化为传递的参数 (initialValue)。返回的对象将在组件的整个生命周期内持续存在。

意思是,您可以用来useRef模仿实例变量,这些变量不会在 props 更改时重新计算。useRef不仅仅用于引用 DOM 元素。

使用外部随机 ID 生成器的示例(例如 loadash)

import React, { useRef } from 'react'
import uniqueId from 'lodash/utility/uniqueId'

function InputField = (props) => {
  const {current: fieldId} = useRef(uniqueId('prefix-'))
  return (
    <div>
      <input id={fieldId} type="checkbox" />
      <label htmlFor={fieldId}>label</label>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

使用简单的自定义随机 ID 生成器的示例

import React, { useRef } from 'react'

function InputField = (props) => {
  const {current: fieldId} = useRef("prefix-" + (Math.random().toString(36)+'00000000000000000').slice(2, 7))
  return (
    <div>
      <input id={fieldId} type="checkbox" />
      <label htmlFor={fieldId}>label</label>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

解释:

上面的随机 ID(Math.random().toString(36)+'00000000000000000').slice(2, 7)来自stackoverflow 答案,并且始终保证5 个字符,相比之下Math.random().toString(16).slice(-4)可能会返回空字符串。

此外,使用前缀也很重要,其中前缀必须以字母开头([A-Za-z])才能成为有效的HTML4 id属性值。