Как генерировать уникальные идентификаторы для форм в React?
У меня есть элементы формы с label
, и я хочу иметь уникальные идентификаторы для ссылки label
на элементы с атрибутом htmlFor
. Что-то вроде этого:
React.createClass({
render() {
const id = ???;
return (
<label htmlFor={id}>My label</label>
<input id={id} type="text"/>
);
}
});
Я использовал для генерации идентификаторов на основе this._rootNodeID
, но его недоступно, так как React 0.13. Каков наилучший и/или самый простой способ сделать это сейчас?
Ответы
Ответ 1
Эти решения отлично подходят для меня.
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.
Обновлено 28.01.2016. Его лучше генерировать идентификатор в componentWillMount
.
Ответ 2
Идентификатор должен быть помещен внутри componentWillMount (обновление для 2018 года) constructor
, не render
. Помещение его в render
будет без необходимости заново генерировать новые идентификаторы.
Если вы используете подчеркивание или 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>
);
}
Ответ 3
Существует множество решений для "клейкой ленты".
Один из них - https://github.com/DelvarWorld/Unique-Id-Mixin
Ответ 4
По состоянию на 2019-04-04, это, кажется, можно сделать с помощью useState
из React Hooks:
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. Существуют также сотни или тысячи других уникальных идентификаторов, но lodash uniqueId
с префиксом должно быть достаточно для выполнения работы.
Обновление 2019-07-10
Спасибо @Huong Hk за указание на ленивое начальное состояние хуков, сумма которого заключается в том, что вы можете передать функцию useState
которая будет запускаться только при начальном монтировании.
// before
const [ id ] = useState(uniqueId('myprefix-'))
// after
const [ id ] = useState(() => uniqueId('myprefix-'))
Ответ 5
Вы можете использовать такую библиотеку, как node-uuid, чтобы убедиться, что вы получаете уникальные идентификаторы.
Установите с помощью:
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>
);
}
}
Ответ 6
Я предпочитаю просто позволить реагировать автоматически генерировать id для меня. Я не совсем уверен, что это правильное использование, поскольку подчеркивание обычно является приватным, но оно делает трюк.
this._reactInternalInstance._rootNodeID
render () {
<button
id={this._reactInternalInstance._rootNodeID}>
{this.props.children}
{/*tooltip */}
<div
htmlFor={this._reactInternalInstance._rootNodeID}
className="mdl-tooltip mdl-tooltip--large">
{this.props.children}
</div>
</button>
}
Ответ 7
Надеюсь, это поможет любому, кто ищет универсальное/изоморфное решение, поскольку проблема контрольной суммы - вот что привело меня сюда в первую очередь.
Как было сказано выше, я создал простую утилиту для последовательного создания нового идентификатора. Поскольку идентификаторы продолжают увеличиваться на сервере и начинаются с 0 в клиенте, я решил reset прирост, каждый из которых начинается с SSR.
// utility to generate ids
let current = 0
export default function generateId (prefix) {
return `${prefix || 'id'}-${current++}`
}
export function resetIdCounter () { current = 0 }
Затем в корневом компоненте или компонентеWillMount вызовите reset. Это существенно сбрасывает область JS для сервера в каждом рендеринге сервера. В клиенте это не оказывает (и не должно) никакого эффекта.
Ответ 8
Вы можете использовать id${new Date().getTime()}
, поскольку new Date(). getTime() возвращает число миллисекунд с 1970/01/01 и отлично работает как уникальный идентификатор.
Следующий функциональный компонент Checkbox создает уникальный идентификатор, используемый в метке и флажке ввода для каждого рендеринга, поэтому его можно переместить на componentWillMount
.
const CheckboxComponent = (props: Props) => {
const uniqueId = `id${new Date().getTime()}`;
return (
<label
htmlFor={uniqueId}
style={[styles.container]}
>
<input
id={uniqueId}
type="checkbox"
style={[styles.spacer]}
{...rest}
/>
{props.label && (
<span style={[styles.label]}>{props.label}</span>
)}
</label>
);
};
const styles = {
label: {
color: "#333",
},
container: {
display: "flex",
flexDirection: "row",
},
spacer: {
flex: 1,
},
};
Ответ 9
Другой простой способ с машинописью:
static componentsCounter = 0;
componentDidMount() {
this.setState({ id: 'input-' + Input.componentsCounter++ });
}
Ответ 10
Я нашел простое решение, как это:
class ToggleSwitch extends Component {
static id;
constructor(props) {
super(props);
if (typeof ToggleSwitch.id === 'undefined') {
ToggleSwitch.id = 0;
} else {
ToggleSwitch.id += 1;
}
this.id = ToggleSwitch.id;
}
render() {
return (
<input id={'prefix-${this.id}'} />
);
}
}
Ответ 11
Не используйте идентификаторы вообще, если вам не нужно, вместо этого оберните ввод в метку, как это:
<label>
My Label
<input type="text"/>
</label>
Тогда вам не нужно беспокоиться об уникальных идентификаторах.