React'te form etiketleri için benzersiz kimlikler nasıl oluşturulur?


129

S'li form öğelerim var ve labels'yi öznitelikli labelöğelere bağlamak için benzersiz kimliklerim olmasını istiyorum htmlFor. Bunun gibi bir şey:

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

Eskiden ID'leri temel this._rootNodeIDalırdım ama React 0.13'ten beri mevcut değil. Bunu şimdi yapmanın en iyi ve / veya en basit yolu nedir?


Bu öğeyi defalarca oluşturuyorsanız, bir for ifadesinde neden yineleyiciyi kullanmayacağınızı varsayıyorum? Bir dizin numarası yeterince iyi değilse, benzersiz bir kılavuz oluşturan bir işlevi de çağırabileceğinizi düşünüyorum. stackoverflow.com/questions/105034/…
Chris Hawkes

1
Farklı bileşenlerde birçok farklı form öğesi vardır ve hepsinin benzersiz kimlikleri olmalıdır. Kimlik oluşturma işlevi, düşündüğüm ve kimse daha iyi bir çözüm önermezse ne yapacağımdır.
Artem Sapegin

3
Bir yerde "global" artan bir sayaç saklayabilir ve onu kullanabilirsiniz. id = 'unique' + (++GLOBAL_ID);nerede var GLOBAL_ID=0;?
WiredPrairie

1
Bu partiye çok, çok geç kaldığımı biliyorum, ancak başka bir alternatif de girdiyi kimlik kullanmak yerine etikete <label>My label<input type="text"/></label>
sarmaktır

Yanıtlar:


85

Bu çözümler benim için iyi çalışıyor.

utils/newid.js:

let lastId = 0;

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

Ve bunu şu şekilde kullanabilirim:

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

Ancak izomorfik uygulamalarda çalışmaz.

17.08.2015 eklendi . Bunun yerine özel NewID ait kullanabileceğiniz işlev UNIQUEID lodash dan.

28.01.2016 tarihinde güncellendi . İçinde kimlik oluşturmak daha iyidir componentWillMount.


3
Çünkü tarayıcıda tekrar 1.den itibaren ID üretmeye başlayacaktır. Ama aslında sunucuda ve tarayıcıda farklı önekler kullanabilirsiniz.
Artem Sapegin

7
Bunu içinde yapma render! Kimliği oluşturuncomponentWillMount
sarink

1
Durum bilgisi olan bir kapsayıcı yaptınız, ancak setState'i kullanmayı ihmal ediyorsunuz ve için spesifikasyonu ihlal ediyorsunuz render. facebook.github.io/react/docs/component-specs.html . Yine de düzeltmesi oldukça kolay olmalı.
aij

3
Yapıcıda lodash'tan uniqueId kullanıyorum ve kimliği ayarlamak için setState kullanıyorum. Yalnızca müşterim olan uygulamam için iyi çalışıyor.
CrossProduct

1
componentWillMountkullanımdan kaldırıldı, bunun yerine yapıcıda bunu yapın. Bakınız: reactjs.org/docs/react-component.html#unsafe_componentwillmount
Vic

79

Kimlik, içine yerleştirilmelidir componentWillMount'un (2018 için güncelleme)constructor , değil render. İçine koymakrender gereksiz yere yeni kimlikler oluşturacaktır.

Alt çizgi veya zigzag kullanıyorsanız, bir uniqueId işlev vardır, dolayısıyla ortaya çıkan kodunuz aşağıdaki gibi olmalıdır:

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 güncellemesi:

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
Ya da kurucuya da koyabilirsiniz.
John Weisz

componentWillMount, React 16.3.0'dan beri kullanımdan kaldırıldı, bunun yerine UNSAFE_componentWillMount'u kullanın, bkz. reactjs.org/docs/react-component.html#unsafe_componentwillmount
lokers

2
React 16.8'deki yeni Hook'larla bunun nasıl yapılacağını kimse önerebilir mi?
Aximili

4
const {current: id} = useRef(_uniqueId('prefix-'))
Kimliğin

1
Kullanım Durumu yerine useRef kullanmanın farkı nedir?
XPD

24

2019-04-04 itibarıyla bu, React Hooks ile başarılabilecek gibi görünüyor 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

Anladığım kadarıyla, güncelleme yapmanıza izin verecek dizi yıkımındaki ikinci dizi öğesini görmezden geliyorsunuz. id ve şimdi bileşenin ömrü boyunca tekrar güncellenmeyecek bir değeriniz var.

Değeri idolacaktır myprefix-<n>burada <n>dönen bir artımlı tamsayı değerdir uniqueId. Bu sizin için yeterince benzersiz değilse, kendi beğeninizi yapmayı düşünün

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

function simpleUniqueId(prefix) {
  return (prefix || '').concat([
    gen4(),
    gen4(),
    gen4(),
    gen4(),
    gen4(),
    gen4(),
    gen4(),
    gen4()
  ].join(''))
}

veya bununla birlikte yayınladığım kütüphaneye bakın: https://github.com/rpearce/simple-uniqueid . Orada yüzlerce veya binlerce başka benzersiz kimlik bilgisi de var, ancak uniqueIdön ekli lodash'lar işi bitirmek için yeterli olmalı.


Güncelleme 2019-07-10

Beni tembel başlangıç ​​durumuna yönlendirdiği için @ Huong Hk'ye teşekkürler , bunun toplamı, useStateyalnızca ilk bağlantıda çalıştırılacak olan bir işlevi iletebilmenizdir .

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

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

1
Bu sayfada bahsedilen diğer birçok yöntemde olduğu gibi sunucu oluşturmada da aynı sorunları yaşıyorum: bileşen tarayıcıda yeni bir kimlikle yeniden oluşturulacak.
Artem Sapegin

@ArtemSapegin: React projesinde, bileşenlerin benzersiz kimliklere sahip olmanın bir yolu olduğunu tartışan bir sorun vardı ( github.com/facebook/react/issues/1137 ), ancak bununla ilgili bir şey olduğunu sanmıyorum. Oluşturulan kimliklerin sunucu ve istemci arasında aynı olması ne kadar önemlidir? Bir için düşünürdüm <input />, neyin olur ki htmlForve idnitelikleri olursa olsun değerlerin ne birbirine bağlanmalıdır.
rpearce

Yeni kimliklerin neden olacağı gereksiz DOM güncellemelerinden kaçınmak önemlidir.
Artem Sapegin

6
2 numaralı fonksiyonun sonucu yerine initialState1 numaralı fonksiyon sağlamanız daha iyidir Yukarıdaki 2 yolun durumu farklı değildir. Ancak farklı olan her yeniden işlenen (# 2) yerine bir kez (# 1) yürütülecektir. Bakınız: Tembel başlangıç ​​durumu: reactjs.org/docs/hooks-reference.html#lazy-initial-state Tembel bir şekilde pahalı nesneler nasıl oluşturulur ?: reactjs.org/docs/…const [ id ] = useState(() => uniqueId('myprefix-'))const [ id ] = useState(uniqueId('myprefix-'))iduniqueId('myprefix-')
Huong Nguyen

1
@HuongHk bu harika; Bilmiyordum! Cevabımı güncelleyeceğim
rpearce

4

Gibi bir kitaplık kullanabilirsiniz Benzersiz kimlikler aldığınızdan emin olmak için bunun için node-uuid .

Şunları kullanarak kurun:

npm install node-uuid --save

Ardından react bileşeninize aşağıdakileri ekleyin:

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
Cevap, şartnameye uyacak şekilde güncellendi gibi görünüyor
Jonas Berlin

2
Sunucuda oluşturulan kimlik, istemcide oluşturulan kimlikten farklı olduğundan, bu izomorfik uygulamalarda çalışmaz.
Daniel T.

2
Ancak yanıtın bir parçası olarak belirtiliyor ki bu çok yanıltıcı
Tom McKenzie

1
EVRENSEL benzersiz kimlikleri kullanmak için Ya, -1, bu dünya boyutunda bir çivi için evren büyüklüğünde bir çekiç.
Jon z

1

Umarım bu, evrensel / izomorfik bir çözüm arayan herkes için yararlıdır, çünkü sağlama toplamı sorunu beni buraya en başta getiren şeydi.

Yukarıda belirtildiği gibi, sırayla yeni bir kimlik oluşturmak için basit bir yardımcı program oluşturdum. Kimlikler sunucuda artmaya devam ettiğinden ve istemcide 0'dan baştan başladığından, SSR'nin başladığı her artışı sıfırlamaya karar verdim.

// utility to generate ids
let current = 0

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

export function resetIdCounter () { current = 0 }

Ve sonra kök bileşenin yapıcısında veya componentWillMount'ta sıfırlamayı çağırın. Bu, esasen her bir sunucu oluşturmada sunucu için JS kapsamını sıfırlar. İstemcide herhangi bir etkisi yoktur (ve olmamalıdır).


İstemciler girişleri 0'dan yeniden adlandırmaya başlarsa, yine de kimlik çatışmaları yaşayabilirsiniz.
Tomasz Mularczyk

@Tomasz, istemcinin form 0 üzerinden yeniden başlamasını istersiniz, böylece sağlama toplamları eşleşir.
tenor528

0

Olağan kullanımlar için labelve input, böyle bir etikete girdi sarmak için sadece kolay:

import React from 'react'

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

Ayrıca, onay kutularında / radyo düğmelerinde kök öğeye dolgu uygulanmasını ve yine de girdiye tıklama geri bildirimi almayı mümkün kılar.


1
Kolaylık için +1 ve bazı durumlarda kullanışlıdır, örneğin selectfarklı konumlarda çoklu etiketler, birleştirilmemiş kullanıcı arabirimi bileşenleri vb. İle kullanılamaz, ayrıca kimliklerin kullanılması önerilir a11y: Genel olarak, açık etiketler yardımcı teknoloji ile daha iyi desteklenir, w3. org / WAI / eğiticiler / formlar / etiketler /…
Michael B.

-1

Bunun gibi kolay bir çözüm buldum:

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

Daktilo ile diğer basit yol:

static componentsCounter = 0;

componentDidMount() {
  this.setState({ id: 'input-' + Input.componentsCounter++ });
}

2
Bu TypeScript olmadan mümkündür
ChrisBrownie55

-1

Benzersiz bir kimlik oluşturucu modülü oluşturuyorum (Typescript):

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

export default uniqueId;

Ve benzersiz kimlikler oluşturmak için üst modülü kullanın:

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

İhtiyaç duymuyorsanız kimlikleri kullanmayın, bunun yerine girişi aşağıdaki gibi bir etikete sarın:

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

O zaman benzersiz kimlikler hakkında endişelenmenize gerek kalmaz.


2
Bu, HTML5 tarafından desteklense de, erişilebilirlik açısından önerilmez: "Ancak bu gibi durumlarda bile, bazı yardımcı teknolojiler etiketler ve gereçler arasındaki örtük ilişkileri anlamadığından, for özniteliğini ayarlamak en iyi uygulama olarak kabul edilir." - developer.mozilla.org/en-US/docs/Learn/HTML/Forms/…
adresinden


1
@BlakePlumb React ekibinin ayrıca erişilebilir bir formlar bölümü vardır: reactjs.org/docs/accessibility.html#accessible-forms
Vic
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.