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

IT技术 reactjs
2021-04-12 11:08:10

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

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

我曾经基于this._rootNodeID生成 ID,但自 React 0.13 以来它不可用。现在最好和/或最简单的方法是什么?

6个回答

id 应该放在componentWillMount (update for 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>
  );
}

2019 年钩子更新:

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

const MyComponent = (props) => {
  // id will be set once when the component initially renders, but never again
  // (unless you assigned and called the second argument of the tuple)
  const [id] = useState(_uniqueId('prefix-'));
  return (
    <div>
      <input id={id} type="checkbox" />
      <label htmlFor={id}>label</label>
    </div>
  );
}
使用 useRef 而不是 use State 有什么区别?
2021-05-24 11:08:10
或者您也可以将其放入构造函数中。
2021-06-02 11:08:10
任何人都可以建议如何使用 React 16.8 中的新 Hooks 来完成这项工作?
2021-06-02 11:08:10
由于您没有跟踪 id 的值,您还可以使用 const {current: id} = useRef(_uniqueId('prefix-'))
2021-06-11 11:08:10
不要将状态用于不是由于给定组件的更改(不变)而引起的事情。概念上是错误的。
2021-06-12 11:08:10

这个解决方案对我来说很好。

utils/newid.js

let lastId = 0;

export default function(prefix='id') {
    lastId++;
    return `${prefix}${lastId}`;
}

我可以这样使用它:

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"/>
        );
    }
});

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

添加 17.08.2015相反,自定义NEWID的功能,您可以使用UNIQUEID从lodash。

2016 年 1 月 28 日更新最好在componentWillMount.

您已经创建了一个有状态容器,但忽略了使用 setState 并且违反了render. facebook.github.io/react/docs/component-specs.html不过应该很容易修复。
2021-06-03 11:08:10
不要这样做render在中创建 idcomponentWillMount
2021-06-05 11:08:10
因为它会在浏览器中再次从第一个开始生成 ID。但实际上您可以在服务器和浏览器中使用不同的前缀。
2021-06-08 11:08:10
你有没有找到同构应用程序的任何解决方案?由于客户端和服务器上的 ID 不同,我得到校验和失败。
2021-06-10 11:08:10
我在构造函数中使用来自 lodash 的 uniqueId 并使用 setState 来设置 id。仅适用于我的客户端应用程序。
2021-06-18 11:08:10

从 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

据我了解,您忽略了数组解构中允许您更新的第二个数组项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(''))
}

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


更新 2019-07-10

感谢@Huong Hk 将我指向hooks lazy initial state,总而言之,您可以将一个函数传递给该函数,useState函数只能在初始安装上运行。

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

// after
const [ id ] = useState(() => uniqueId('myprefix-'))
我在服务器渲染方面遇到了与此页面上提到的许多其他方法相同的问题:组件将在浏览器中使用新 ID 重新渲染。
2021-05-26 11:08:10
@ArtemSapegin:React 项目中存在一个问题(github.com/facebook/react/issues/1137),讨论如何让组件具有唯一 ID,但我认为没有任何结果。服务器和客户端之间生成的 ID 相同有多重要?我认为对于<input />,重要的是无论值是什么,都应该将htmlForid属性联系在一起。
2021-05-26 11:08:10
@HuongHk 太棒了;我不知道!我会更新我的答案
2021-06-10 11:08:10
如果你提供一个函数作为initialState#1const [ id ] = useState(() => uniqueId('myprefix-'))而不是函数 #2 的结果,const [ id ] = useState(uniqueId('myprefix-')) 状态:id上面的两种方式并没有什么不同。但不同的是uniqueId('myprefix-')将执行一次(#1)而不是每次重新渲染(#2)。请参阅:延迟初始状态:reactjs.org/docs/hooks-reference.html#lazy-initial-state如何延迟创建昂贵的对象?:reactjs.org/docs/...
2021-06-11 11:08:10
避免不必要的 DOM 更新很重要,因为新 ID 会导致这种更新。
2021-06-18 11:08:10

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

安装使用:

npm install node-uuid --save

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

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>
    );
  }   
}
答案似乎已更新以符合规范
2021-06-06 11:08:10
这在同构应用程序中不起作用,因为服务器上生成的 id 与客户端上生成的 id 不同。
2021-06-08 11:08:10
但它被列为答案的一部分,这是非常具有误导性的
2021-06-15 11:08:10
“ID 太独特了”似乎是拒绝投票的任意理由。UUID 并不昂贵。
2021-06-15 11:08:10
2021-06-18 11:08:10

希望这对任何寻求通用/同构解决方案的人都有帮助,因为校验和问题首先是导致我来到这里的原因。

如上所述,我创建了一个简单的实用程序来顺序创建一个新的 id。由于 ID 在服务器上不断增加,而在客户端从 0 开始,我决定在每次 SSR 启动时重置增量。

// utility to generate ids
let current = 0

export default function generateId (prefix) {
  return `${prefix || 'id'}-${current++}`
}

export function resetIdCounter () { current = 0 }

然后在根组件的构造函数或 componentWillMount 中,调用重置。这实质上是在每个服务器渲染中重置服务器的 JS 范围。在客户端它没有(也不应该)有任何影响。

@Tomasz 您希望客户端从表单 0 重新开始,以便校验和匹配。
2021-06-10 11:08:10
如果客户端再次从 0 开始命名输入,您仍然可能会发生 id 冲突。
2021-06-20 11:08:10