12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【React】useRef ~2つの使い方とその背景~

Posted at

はじめに

あるinput要素が画面に表示された時に、デフォルトでフォーカスをあててinput要素をクリックしなくても入力できる状態にしたいという場面があり、ReactではuseRefというhooksを使ってこれを実装できることを知った。

さらに調べてみると、useRef の活用方法や背景は興味深いものだったので、記事にまとめておく。

useRefとは

ドキュメントから抜粋すると、以下のように紹介されている。

本質的に useRef とは、書き換え可能な値を .current プロパティ内に保持することができる「箱」のようなものです。

主な使用方法は2種類

  • DOMへのアクセス
    例:input要素にフォーカスする

  • 値を保持する
    useStateとの大きな違いは、値を更新しても再レンダリングを起こさないこと。

使用方法①:DOMへのアクセス

useRefref を使うと、DOMへアクセスすることができる。

例えば、特定のinput要素にアクセスし、その要素に対してJavaScriptのfocusメソッドを使ってフォーカスをあてるというように使う。

<input id="name" /> のinput要素にフォーカスしたい場合、JavaScriptでは document.getElementById('name').focus() というように書くが、これと同じことをReactで行いたい場合にuseRefを使う。

使ってみる

通常input要素に入力をするには、画面が描画されたらinput要素をクリックするなどしてフォーカスを当てなければいけない。

そこでuseRefを使い、画面描画された時点でinput要素にフォーカスを当ててみる。

import { useEffect, useRef } from 'react'

export default function App() {
  const inputRef = useRef(null)    // 1. useRefの初期化
  console.log(inputRef)

  useEffect(() => {
    inputRef.current.focus()    // 3. 使用する
    console.log(inputRef)
  },[])

  return (
    <div className="App">
      <input ref={inputRef} />    // 2. ref属性に設定
    </div>
  );
}

以下のcodesandboxのサンプルコードの通り、表示した時点でinput要素にフォーカスが当たっていることが確認できる。

useRef の構文

const オブジェクトを受け取る変数 = useRef(初期値)

useRefから返されるオブジェクトは current というプロパティを持ち、この current では書き換え可能な値を持つことが出来る。

上記の例では、以下のようにinputRefcurrentプロパティにinput要素を設定し、JavaScriptを使ってその要素を操作したことになる。

// useRefの初期化
const inputRef = useRef(null);

// inputRefのcurrentプロパティにinput要素を設定する
<input ref={inputRef} />

また、上記の通りinput要素にrefを指定した状態で以下のように記述すれば、input要素の中身を操作することもできる。

inputRef.current.value = 'あいうえお';

refとuseRefの背景

次に「使用方法②:値を保持する」の説明に入る... 前に、useRefができた背景を知って筆者は理解が深まったので、先に紹介する。

hooks誕生前

useRefというhooksを使って、より便利にrefを参照できるようになったわけだが、ref自体はhooksが生まれる前からDOMやReact要素にアクセスする方法として提供されてきた。

Ref は render メソッドで作成された DOM ノードもしくは React の要素にアクセスする方法を提供します。

hooks誕生後

useRef は単純なDOMへのアクセス(使用方法①)だけでなく、値を保持する(使用方法②)という用途も提供する。

しかしながらuseRef() は ref 属性で使うだけではなく、より便利に使えます。これはクラスでインスタンス変数を使うのと同様にして、あらゆる書き換え可能な値を保持しておくのに便利です。

 
このように、先に説明した使用方法①は従来からのrefの使用法であり、次に説明する使用方法②はuseRefというhooksが誕生したことにより、ref属性をこんな風にも使えますよ〜〜と紹介されている機能といえる。

使用方法②:値を保持する

最初にも少し紹介したが、useRefが返すオブジェクトのcurrentプロパティは書き換え可能な値を保持することが出来る。

useStateも値を保持することが出来るが、useStateと違いuseRefでは値を更新してもコンポーネントの再レンダリングが起きない。

useRef は中身が変更になってもそのことを通知しないということを覚えておいてください。.current プロパティを書き換えても再レンダーは発生しません。

useStateとuseRefの挙動をくらべる

useStateuseRef、それぞれが保持する値を更新した時の挙動を比べてみる。

import { useState, useRef } from "react";

export default function App() {
  const [countState, setCountState] = useState(0);
  const countRef = useRef(0);
  const handleStateClick = () => setCountState(countState + 1);
  const handleRefClick = () => countRef.current++;

  console.log("レンダリング!");

  return (
    <div className="App">
      <p>{countState}</p>
      <button onClick={handleStateClick}>state +1</button>

      <p>{countRef.current}</p>
      <button onClick={handleRefClick}>ref +1</button>
    </div>
  );
}

以下のcodesandboxのサンプルコードで挙動を確認してみると、useRefの値を更新してもレンダリングが起きないが、useStateの値を更新すると毎回レンダリングが起きることが分かる。

最後に

私が今回業務でuseRefを使用したのは、使用方法①の使い方のみだった。
使用方法②についても、挙動は理解したが具体的な活用シーンが特に思い浮かんでいないので、有効に活用されているコードを見てみたい。

また今回TypeScriptで実装したのだが、useRefを使う際の型にもルールがあることを学んだので、改めて別の記事にまとめようと思う。

参考記事

12
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?