Function Component のインスタンスごとに一意な値を割り振る

  • react
  • javascript

React v16.8+ のお話。
hooks を利用して、 Function Component のインスタンスごとに一意な値を割り当てる方法。

useInstanceId.tsx
import React from 'react'

let counter = 0

const useInstanceId = (): number => {
  const ref = React.useRef<number | null>(null)

  if (ref.current === null) {
    ref.current = counter += 1
  }

  return ref.current
}
DemoComponent.tsx
import React from 'react'
import { useInstanceId } from './useInstanceId'

const Example = () => {
  const id = useInstanceId()

  return <span>{id}</span>
}

こうすると DemoComponent コンポーネントのインスタンスごとに一意な id が割り振られる。 Ref を用いることで再描画が発生しても id は変わらない。 この方法はインスタンス変数を使う方法として公式ドキュメントに載っていた。

インスタンス変数のようなものはありますか? | フックに関するよくある質問 – React

React.useRef() で返るオブジェクトは MutableRefObject として定義されており、 current プロパティが読み書き可能になっている。 そこに値をセットして使うというもの。

let counter が気になる気がしないでもないが、まあしゃーなし。

ユースケースとしてはこんな感じ。

import React from 'react'
import { useInstanceId } from './useInstanceId'

const ExamplePanel = (props: { children: React.ReactNode }) => {
  const id = useInstanceId()

  return (
    <>
      <button aria-controls={'demo-pane-' + id}>トグルする</button>
      <div id={'demo-pane-' + id}>{props.children}</div>
    </>
  )
}

実装はいろいろ省略しているが、 汎用的なコンポーネント内で id 属性を使う場合は値の重複を避けたい。 そんなときに使える。

ちなみに

以下の書き方でも一意な値を得ることはできるが、 これだと render が発生する度に id が変わってしまう。
それにより本来不要な属性の値を変更する処理が走るので(微々たるものだとは思うが)パフォーマンス的にイマイチ。

import React from 'react'

let counter = 0

const ExamplePanel = (props: { children: React.ReactNode }) => {
  const id = (counter += 1)

  return (
    <>
      <button aria-controls={'demo-pane-' + id}>トグルする</button>
      <div id={'demo-pane-' + id}>{props.children}</div>
    </>
  )
}

おわり。

Send edit request via GitHub.