ReactのRefの使い方をcreateRefやuseRefを使って解説!

こんにちわ。

 

今日の記事では、ReactのRefについて解説をしていきたいと思います。

 

もし、これまでエンジニアとしての経験があれば、JavaScriptのDOM操作に関しては知ってると思います。

 

Reactでは、今までjQueryなどで行っていた煩雑なDOM操作をより簡単に、リッチなUIで実現できます。

 

そしてその中でも、ReactのRefの様々な扱い方を知ることで、より深くDOM操作のやり方を覚えることが出来ると思うので、

 

是非最後まで読んでみてください。

 

ReactのRefとDomとは何か?

 

Reactには、コンポーネントからDOMにアクセスするためのrefという機能がありまして、

 

アプリケーション内の要素にrefをアタッチするだけで、

 

コンポーネント内のどこからでもその要素のDOMにアクセスできるようになります。

 

要するにrefとは、DOMの参照を保持するということなのですね。

 

また、Refsは、DOMノードだけでなく、Reactの要素に直接アクセスするためにも使用できます。Reactのドキュメントには、refsに関して以下のように書かれています。

 

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

 

ReactでのRefの作成する方法

 

Reactには、Refを作成するための3つの主要な方法があります。

 

ここでは、それぞれの方法を古いものから順にご紹介します。

  • String refs(レガシーメソッド)
  • コールバックRef
  • React.createRef (React 16.3より)
  • useRefフック (React 16.8より)

String refs(レガシーメソッド)

Reactアプリケーションでrefを作成するレガシーな方法は、

 

string refsを使用することです。

 

これは最も古い方法であり、Reactの将来のリリースでは削除されるため、レガシーまたは非推奨とされています。

 

目的の要素にref propを追加し、その値としてrefの文字列名を渡すことでstring refsを表現できます。

 

 

class MyComponent extends React.Component {

  constructor(props) {
    super(props);
    this.toggleInputCase = this.toggleInputCase.bind(this);
    this.state = { uppercase: false };
  }
  
  toggleInputCase() {
    const isUpper = this.state.uppercase;
    
    // Accessing the ref using this.refs.inputField
    const value = this.refs.inputField.value;
    
    this.refs.inputField.value =
      isUpper
        ? value.toLowerCase()
        : value.toUpperCase();
        
    this.setState({ uppercase: !isUpper });
  }

  render() {
    return (
      <div>
        {/* Creating a string ref named: inputField */}
        <input type="text" ref="inputField" />
        
        <button type="button" onClick={this.toggleInputCase}>
          Toggle Case
        </button>
      </div>
    );
  }
  
}

 

<input>要素と<button>要素をレンダリングするシンプルなReactコンポーネントを作成し、入力の大文字と小文字を切り替えることができます。

 

コンポーネントの状態を初期化し、uppercaseプロパティをfalseに設定してますけど、

 

このプロパティにより、入力の現在のケースを決定しています。

 

強調したいのは、<input>要素に作成した文字列の参照で、

 

inputFieldという名前の<input>要素へのrefも作成しました。

 

その後、<button>のクリックイベントハンドラで、this.refs.inputFieldを介してrefにアクセスしています。

 

そして、<input>要素のDOMを操作して、入力の値を変更しています。

Reactでのコールバックrefの使用

コールバックrefは、refの名前を文字列で渡す代わりに、

 

refの作成にコールバック関数を使用します。

 

Reactのバージョン16.3より前のバージョンを使用している場合は、

 

この方法でrefを作成することをお勧めします。

 

コールバック関数は、ReactコンポーネントのインスタンスやHTMLのDOM要素を引数として受け取り、

 

それを別の場所に保存してアクセスすることができます。

 

コールバックrefを使うと、先ほどのコードスニペットは以下のようになります。

 

class MyComponent extends React.Component {

  constructor(props) {
    super(props);
    this.toggleInputCase = this.toggleInputCase.bind(this);
    this.state = { uppercase: false };
  }
  
  toggleInputCase() {
    const isUpper = this.state.uppercase;
    
    // Accessing the ref using this.inputField
    const value = this.inputField.value;
    
    this.inputField.value =
      isUpper
        ? value.toLowerCase()
        : value.toUpperCase();
        
    this.setState({ uppercase: !isUpper });
  }

  render() {
    return (
      <div>
        {/* Creating a callback ref and storing it in this.inputField */}
        <input type="text" ref={elem => this.inputField = elem} />
        
        <button type="button" onClick={this.toggleInputCase}>
          Toggle Case
        </button>
      </div>
    );
  }
  
}

 

ここでは2つの大きな変更を加えています。

 

まず、コールバック関数を使ってrefを定義し、それをthis.inputFieldに格納しました。

 

 

<input type="text" ref={elem => this.inputField = elem}. />

 

そして、イベントハンドラの中で、this.refs.inputFieldではなく、this.inputFieldを使ってrefにアクセスします。

 

今回の例のようにインラインのコールバック Ref を使用する場合、

 

通報ではコンポーネントが更新されるたびに、コールバック関数が 2 回呼び出されるのですが

 

(最初は null で、次に DOM 要素で)

 

コールバック関数をコンポーネントクラスのバウンドメソッドとして作成することで、

 

この動作を回避することができます。

 

refの作成にコールバック関数を使用することでより細かく制御することができます。

 

React.createRefの使用

React 16.3以降では、

 

React APIにはcreateRef()メソッドが含まれており、コールバック関数を使用したのとほぼ同じ方法で、

 

refを作成するのに使用できます。

 

React.createRef()を呼び出してrefを作成し、その結果のrefを要素に割り当てるだけです。

 

React.createRef()を使うと、先ほどの例は以下のようになります。

 

class MyComponent extends React.Component {

  constructor(props) {
    super(props);
    this.inputField = React.createRef();
    this.toggleInputCase = this.toggleInputCase.bind(this);
    this.state = { uppercase: false };
  }
  
  toggleInputCase() {
    const isUpper = this.state.uppercase;
    
    // Accessing the ref using this.inputField.current
    const value = this.inputField.current.value;
    
    this.inputField.current.value =
      isUpper
        ? value.toLowerCase()
        : value.toUpperCase();
        
    this.setState({ uppercase: !isUpper });
  }

  render() {
    return (
      <div>
        {/* Referencing the ref from this.inputField */}
        <input type="text" ref={this.inputField} />
        
        <button type="button" onClick={this.toggleInputCase}>
          Toggle Case
        </button>
      </div>
    );
  }
  
}

 

ここではいくつかの変更点があります。

 

まず、コンストラクタ()の中で、React.createRef()を使ってRefを作成し、以下のようにthis.inputFieldに格納しています。

 

 

this.inputField = React.createRef();

 

次に、イベントハンドラの中で、this.inputFieldではなくthis.inputField.currentを使ってrefにアクセスします。

 

これは、React.createRef()で作成されたrefについて注目すべきばしょです。

 

ノードへの参照は、refのcurrent属性でアクセスできるようになります。

 

最後に、以下のように<input>コンポーネントにrefを渡します。

 

<input type="text" ref={this.inputField} />

 

ここまで、Reactアプリケーションでrefを作成するさまざまな方法を探ってきましけども、

 

次は、React.createRef.のより興味深い特徴を詳しく見ていきます。

 

ReactのuseRefフックを使う

React v16でリリースされたHooks APIは、

 

Reactアプリケーションでコードを抽象化して再利用するためのデファクトの手段となっています。

 

そのようなHookの一つがuseRefであり、機能的なコンポーネントにrefを作成して使用することができます。

 

useRef フックを使用するには、ref.current が参照するべきオブジェクトを useRef フックに渡し、

 

それを呼び出します。

 

このHookの呼び出しは、前述のcreateRefメソッドを使用しているかのように使用できるrefオブジェクトを返すはずで、

 

先ほどの例で useRef Hook を使用した場合、以下のようになります。

 

 

const MyComponent = () => {
    const [uppercase, setUppercase] = React.useState(false)
    const inputField = React.useRef(null)
    const toggleInputCase = () => {
        // Accessing the ref using inputField.current
        const value = inputField.current.value;
        inputField.current.value = uppercase ? value.toLowerCase() : value.toUpperCase();
        setUppercase(previousValue => !previousValue)
    }

    return(
       <div>
           {/* Referencing the ref from this.inputField */}
           <input type="text" ref={inputField} />
           <button type="button" onClick={toggleInputCase}>
                Toggle Case  
           </button>
       </div>

 

 

短くきれいになりました。

 

ご覧の通り、コードはReact.createRefの実装とよく似ていますけども、

 

useRef Hookを使ってrefを作成し、そのrefを<input> HTML要素のref属性に渡しています。

 

<button>要素のイベントハンドラについても、処理は先ほどと同じです。

 

状態変数 uppercase の現在の値に応じて、ref が指す HTML 要素の value プロパティを更新します (ref.current を使ってアクセスできます)。

 

以上になります。

 

今日の記事では、英語の記事のHow to use React createRef を参考に記事を書きました。

 

分かりやすくするため一部、割愛したりしてますので、もっと詳しく原文で見たい人はそちらへどうぞ。

 

*参考記事

藤沢瞭介(Ryosuke Hujisawa)
  • りょすけと申します。18歳からプログラミングをはじめ、今はフロントエンドでReactを書いたり、AIの勉強を頑張っています。off.tokyoでは、ハイテクやガジェット、それからプログラミングに関する情報まで、エンジニアに役立つ情報を日々発信しています!

未整理記事

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です