React에서 양식 레이블에 대한 고유 ID를 생성하는 방법은 무엇입니까?


128

labels 가있는 양식 요소가 있고 s labelhtmlFor속성 이있는 요소 에 연결하는 고유 ID를 갖고 싶습니다 . 이 같은:

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

나는 기반으로 ID를 생성 this._rootNodeID했지만 React 0.13 이후로는 사용할 수 없습니다. 지금 가장 좋고 / 또는 가장 간단한 방법은 무엇입니까?


이 요소를 반복해서 생성하는 경우 for 문에서 반복자를 사용하지 않는 이유는 무엇입니까? 인덱스 번호가 충분하지 않은 경우 고유 한 GUID를 생성하는 함수를 호출 할 수도 있습니다. stackoverflow.com/questions/105034/…
Chris Hawkes 2015

1
서로 다른 구성 요소에는 다양한 양식 요소가 있으며 모두 고유 한 ID를 가져야합니다. ID를 생성하는 기능은 내가 생각한 것이고 아무도 더 나은 솔루션을 제안하지 않으면 무엇을 할 것인가입니다.
Artem Sapegin 2015

3
"전역"증가 카운터를 어딘가에 저장하고 사용할 수 있습니다. id = 'unique' + (++GLOBAL_ID);어디 var GLOBAL_ID=0;?
WiredPrairie

1
나는 아주, 아주 늦게 자에게있어 알고 있지만 다른 대안은, 사용하는 ID를 대신 라벨의 입력을 래핑하는 것입니다 예를 들면 :<label>My label<input type="text"/></label>
마이크 Desjardins에

답변:


85

이 솔루션은 저에게 잘 작동합니다.

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 함수 대신 lodash 에서 uniqueId 를 사용할 수 있습니다 .

업데이트 : 2016 년 1 월 28 일 . .NET에서 ID를 생성하는 것이 좋습니다 componentWillMount.


3
브라우저에서 다시 첫 번째부터 ID를 생성하기 시작하기 때문입니다. 그러나 실제로 서버와 브라우저에서 다른 접두사를 사용할 수 있습니다.
Artem Sapegin 2015 년

7
에서 이것을하지 마십시오 render! ID 만들기componentWillMount
sarink

1
상태 저장 컨테이너를 만들었지 만 setState 사용을 게을리하고에 대한 사양을 위반하고 render있습니다. facebook.github.io/react/docs/component-specs.html . 그래도 고치는 것은 매우 쉽습니다.
aij

3
생성자에서 lodash의 uniqueId를 사용하고 setState를 사용하여 ID를 설정합니다. 내 클라이언트 전용 앱에서 잘 작동합니다.
CrossProduct 2016-04-12

1
componentWillMount더 이상 사용되지 않습니다. 대신 생성자에서이 작업을 수행하십시오. 참조 : reactjs.org/docs/react-component.html#unsafe_componentwillmount
Vic

78

ID는 .NET이 아닌 componentWillMount (2018 년 업데이트) 내에 있어야합니다 . 그것을 넣으면 불필요하게 새 ID가 다시 생성됩니다.constructorrenderrender

밑줄이나 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 Hooks 업데이트 :

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

11
또는 생성자에 넣을 수도 있습니다.
John Weisz

componentWillMount는 React 16.3.0부터 더 이상 사용되지 않습니다. 대신 UNSAFE_componentWillMount를 사용하세요. reactjs.org/docs/react-component.html#unsafe_componentwillmount
lokers

2
React 16.8의 새로운 Hooks로 이것이 어떻게해야하는지 제안 할 수 있습니까?
Aximili

4
ID 값을 추적하지 않기 때문에 다음을 사용할 수도 있습니다const {current: id} = useRef(_uniqueId('prefix-'))
forivall

1
Use State 대신 useRef를 사용하는 것과 다른 점은 무엇입니까?
XPD

24

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에게 게으른 초기 상태연결 하도록 알려 주셔서 감사합니다. 이의 합계 useState는 초기 마운트에서만 실행 되는 함수를 전달할 수 있다는 것입니다.

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

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

1
이 페이지에서 언급 한 다른 많은 방법과 마찬가지로 서버 렌더링에도 동일한 문제가 있습니다. 구성 요소는 브라우저에서 새 ID로 다시 렌더링됩니다.
Artem Sapegin

@ArtemSapegin : React 프로젝트에 구성 요소가 고유 한 ID를 가질 수있는 방법을 논의 하는 문제 ( github.com/facebook/react/issues/1137 )가 있었지만, 그 어떤 것도 발생했다고 생각하지 않습니다. 생성 된 ID가 서버와 클라이언트간에 동일하다는 것이 얼마나 중요합니까? 나는이에 대한 그런 생각 <input />, 무슨 일이 있어도 것은 것입니다 htmlForid특성에 상관없이 값이 무엇인지 서로 연결되어서는 안된다.
rpearce

새로운 ID로 인해 발생하는 불필요한 DOM 업데이트를 피하는 것이 중요합니다.
Artem Sapegin

6
함수 # 2의 결과 대신 initialState# 1 로 함수를 제공하는 것이 더 좋습니다 . 상태 : 위의 두 가지 방법은 다르지 않습니다. 그러나 다른 것은 다시 렌더링 될 때마다 (# 2) 대신 한 번 (# 1) 실행됩니다. 참조 : 게으른 초기 상태 : reactjs.org/docs/hooks-reference.html#lazy-initial-state 어떻게 유유히 고가의 개체를 만드는 데? reactjs.org/docs/...const [ id ] = useState(() => uniqueId('myprefix-'))const [ id ] = useState(uniqueId('myprefix-'))iduniqueId('myprefix-')
흐엉이라는 응웬

1
@HuongHk 정말 놀랍습니다. 나는 몰랐다! 내 답변을 업데이트하겠습니다
rpearce 19

4

이를 위해 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>
    );
  }   
}


2
답변은 사양을 준수하도록 업데이트 된 것으로 보입니다
Jonas Berlin

2
서버에서 생성 된 ID가 클라이언트에서 생성 된 ID와 다르기 때문에 동형 앱에서는 작동하지 않습니다.
다니엘 T.

2
그러나 그것은 매우 잘못된 것입니다 해답의 한 부분으로 언급한다
톰 맥켄지

1
Ya, UNIVERSALLY 고유 ID를 사용하는 경우 -1, 그것은 세계 크기의 못을위한 우주 크기의 망치입니다.
Jon z

1

체크섬 문제가 처음부터 나를 이끈 이유이기 때문에 범용 / 동형 솔루션을 찾는 모든 사람에게 도움이되기를 바랍니다.

위에서 말했듯이 순차적으로 새 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 범위를 재설정합니다. 클라이언트에서는 효과가 없습니다.


클라이언트가 0부터 입력 이름을 다시 지정하기 시작하면 여전히 ID 충돌이 발생할 수 있습니다.
Tomasz Mularczyk

@Tomasz는 체크섬이 일치하도록 클라이언트가 양식 0에서 다시 시작하기를 원합니다.
tenor528

0

label및 의 일반적인 사용법의 경우 다음 과 input같이 입력을 레이블로 래핑하는 것이 더 쉽습니다.

import React from 'react'

const Field = props => (
  <label>
    <span>{props.label}</span>
    <input type="text"/>
  </label>
)      

또한 체크 박스 / 라디오 버튼에서 패딩을 루트 요소에 적용하고 여전히 입력에 대한 클릭 피드백을받을 수 있습니다.


1
편의성을 위해 +1하고 일부 경우에 유용합니다. 예를 들어 select다른 위치의 다중 레이블, 결합되지 않은 ui 구성 요소 등과 함께 사용할 수없는 -1 , ID도 사용하는 것이 좋습니다. a11y : 일반적으로 명시 적 레이블은 보조 기술 w3에서
Michael B.

-1

다음과 같은 쉬운 해결책을 찾았습니다.

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


-1

uniqueId 생성기 모듈 (Typescript)을 만듭니다.

const uniqueId = ((): ((prefix: string) => string) => {
  let counter = 0;
  return (prefix: string): string => `${prefix}${++counter}`;
})();

export default uniqueId;

그리고 최상위 모듈을 사용하여 고유 ID를 생성하십시오.

import React, { FC, ReactElement } from 'react'
import uniqueId from '../../modules/uniqueId';

const Component: FC = (): ReactElement => {
  const [inputId] = useState(uniqueId('input-'));
  return (
    <label htmlFor={inputId}>
      <span>text</span>
      <input id={inputId} type="text" />
    </label>
  );
};     

-3

필요하지 않은 경우 ID를 전혀 사용하지 말고 대신 다음과 같은 레이블로 입력을 래핑하십시오.

<label>
   My Label
   <input type="text"/>
</label>

그러면 고유 ID에 대해 걱정할 필요가 없습니다.


2
이는 HTML5에서 지원되지만 접근성 측면에서는 권장되지 않습니다. "그러나 이러한 경우에도 일부 보조 기술은 레이블과 위젯 간의 암시 적 관계를 이해하지 못하기 때문에 for 속성을 설정하는 것이 모범 사례로 간주됩니다." -에서 developer.mozilla.org/en-US/docs/Learn/HTML/Forms/...
GuyPaddock


1
반작용 @BlakePlumb 팀은 또한 접근 가능한 형태의 섹션이 있습니다 reactjs.org/docs/accessibility.html#accessible-forms를
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.