useRef を書きながら学ぶ を書きながら学ぶ（React Hooks 入門シリーズ 3/6）

## ロードマップ

React 16.8 で追加された機能であるReactの`Hooks`について書いてあります。

書きながら学ぶ React Hooks 入門シリーズとして書き下ろしました。

- [React.memo / useCallback / useMemo](https://qiita.com/ryosuketter/items/c503d98e16c28f516c4d)
- [Context / useContext](https://qiita.com/ryosuketter/items/90bd9edd5d91b8daf5c9)
- [useRef](https://qiita.com/ryosuketter/items/f2cc554cc89fb41d5a0b) :point_left_tone2: 今回
- [useState](https://qiita.com/ryosuketter/items/40dfc139ed90ebffd284)
- [useEffect](https://qiita.com/ryosuketter/items/6551ee0d75a3da003980)
- [useReducer](https://qiita.com/ryosuketter/items/3d59f1c503fe27fa0cb9)

## はじめに

Reactの組み込みフックであると`useRef`の説明をします。

## useRef とは

ref オブジェクト ( React.createRef の戻り値 ) を返すフックです。これを利用することで、DOMの参照や、コンポーネント内で値を保持できます。

**値を保持する** と言う点は useState と同じですが、異なる点は、useRef で生成した値を更新してもコンポーネントは再レンダリングされないことです。

なので、レンダリングには関係ない state を扱いたい時（例：コンポーネント内で値を保持したいが、値を更新してもコンポーネントを再レンダリングしたくない時）などに利用します。

### 構文

```js
const refオブジェクト = useRef(初期値)
```

引数に渡した値が、refオブジェクトのカレントプロパティの値になります。

再度になりますが、refオブジェクトは更新しても再レンダリングされません。

今回は、useRefの主な活用方法を2つ紹介します

### 活用方法1...JSX内のノードに対してミュータブルな状態にしてアクションを起こせる状態にする

初回レンダリング時に、inputフィールドにFocusされるモノを作成します。

<details><summary>サンプルコード</summary><div>

```js:App.js
import React from "react";
import Input from "./components/Input";

const App = () => {
  return (
    <div className="App">
      <p>useRef</p>
      <Input />
    </div>
  );
};

export default App;
```

```js:/components/Input.js
import React, { useEffect, useRef } from "react";

const Input = () => {
  // useRefを使ってRefオブジェクトを作成。初期値はnull
  const inputRef = useRef(null);
  useEffect(() => inputRef.current.focus(), []);
  // useRefによって作成されたRefオブジェクトをInputフィールドのrefプロパティに持たせることによって
  // refオブジェクトのカレントプロパティ内にInputノードが格納されてアクセス可能になります
  return <input ref={inputRef} type="text" />;
};

export default Input;
```

</div></details>

補足として、useRefとして作成されたオブジェクトはすでにカレントプロパティを持っていて、useRef(初期値)で渡したnullがそれです。

![ad59451e249a01452b0bbdb979f4b3c5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/796859c1-fefe-903f-5437-6c362f6d0213.gif)

リロードしても、初めからInputフィールドにフォーカスが当たっていることが分かります。

このように、JSX内のノードに対してミュータブルな状態にしてアクションを起こせる状態にすることがuseRefの１つの活用方法です。

### 活用方法2...クロージャ内で宣言された値へアクセスしたい場合の活用方法

1秒ごとに保持する値を更新させ、
ボタンクリックアクションでその更新を止めたい時どうやるか？
useRefを活用して作成します。

<details><summary>サンプルコード</summary><div>

```js:App.js
import React from "react";
import Count from "./components/Count";

const App = () => {
  return (
    <div className="App">
      <p>useRef</p>
      <Count />
    </div>
  );
};

export default App;
```

```js:/components/Count.js
import React, { useState, useEffect, useRef } from "react";

const Count = () => {
  // カウントのためのState
  const [count, setCount] = useState(0);
  const intervalRef = useRef();
  // ライフサイクルメソッドの中に組み込みたいのでuseEffect
  useEffect(() => {
    intervalRef.current = setInterval(() => {
      setCount((prevCount) => prevCount + 1);
    }, 1000);
    // アンマウント時の処理
    return () => {
      clearInterval(intervalRef.current);
    };
  }, []);
  return (
    <div className="Count">
      <p>{count}</p>
      <button
        onClick={() => {
          // setIntervalを実行するuseRefのカレントプロパティに入れることで
          // onClick次の処理として使えるようになる
          // useEffect 内のローカル変数として使われるとここからはアクセスできないけど
          // intervalRef.current だとアクセスが可能になる
          clearInterval(intervalRef.current);
        }}
      >
        Stop
      </button>
    </div>
  );
};

export default Count;
```

</div></details>

![eeb77af50ca0a7b5880348e728f1b0eb.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/d4a2dc66-4d52-7d6a-df3e-9df3151d0262.gif)

今回は以上です。

## 参考

https://ja.reactjs.org/tutorial/tutorial.html