1.はじめに
最近 TypeScript の記事を書き始めてだいぶ JavaSrcipt や TypeScript の苦手意識は減りましたが、React は難しいなと感じる今日この頃です。
Reactの基礎がわかっていないなと感じ Hook 関係の記事を書いて基礎力をつけたいなと思い本記事を書き始めました。
記事を書くことで React の苦手意識も克服したいなと思っています。
第一弾として、useState
についてキャッチアップしたので記事にします。
同じように React に抵抗感を持たれてる方に読んでいただけますと幸いです。
したがって、本記事は React の 超 基礎の記事となっています。
もし間違って認識しているところ等ありましたらご指摘いただけますと幸いです。
2.目次
1.はじめに
2.目次
3.この記事でわかること
4.環境
5.useState とは
5.1.state とは? Hookとは?
5.2.useState とは
5.3.useState の更新関数の引数
6.おわりに
7.参考
3.この記事でわかること
本記事を読むことで React の Hook の苦手意識をなくすことができます。
- Hook の役割を理解できる
-
usestate
の挙動を理解できる -
useState
を使えるようになれる
読み終える頃には 「useState
完全に理解した!!」と言えるようになっているはずです。
4.環境
- React: 17.0.2
- TypeScript: 4.4.2
5.useStateとは
Hook や state とはどんなものかの概要を理解してから useState
に入る方がいいと思いますので、
まずは、そこから抑えていきましょう。
5.1.stateとは? Hookとは?
まず、 useState
の説明に入る前に、state や Hook とは何かについて振れておきます。
state とは、
- コンポーネント(再利用できる部品)の描画(ブラウザに表示)後に変更する値のこと
Hook とは、
- コンポーネントとは独立した関数
- コンポーネントに対して着脱可能な機能を取り付ける(hook up)もの
- 関数コンポーネントで state を実装するときに使う
今回は、コンポーネントに state を追加する useState
についての触れていきたいと思います。
Hook の基礎の基礎であろう useState
がどんな動きをするのか全くわかっていませんでした。
同じ境遇をお持ちの方に読んでいただけると幸いです。
5.2.useState とは
今回はクリックしたら数が増える Counter
というコンポーネントを用いて useState
がどのような動きをするのかを見ていきたいと思います。
ソースは以下の通りです。
import { useState } from "react";
export const Counter = () => {
// useState フックを使ってクリックの回数をステート管理
const [count, setCount] = useState<number>(0);
return (
<div>
<p>{count} 回クリックしました。</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
useState
はこのように配列の分割代入を用いて記述します。
const [count, setCont] = useState<number>(0);
(分割代入をキャッチアップするまでは、このソースコードの意味が全くわかりませんでしたね…)
以前、分割代入の記事を書いたので、そちらを読んでいただけると分割代入の理解が深まるかと思います。
それでは、useState
を読み解いていきましょう。
const [count, setCont] = useState<number>(0);
useState
は、この部分ですね。
まずは、useState<number>(0)
ですが、
- state の引数は number 型
- state の初期値は 0
という意味になります。
(初期値 0 を定義していなかった場合は、undefined となります )
次に useState
の式全体を見てみます。
const [count, setCont] = useState<number>(0);
は、配列の分割代入を使っているので、
// この 0 は useState<number>(0) の 初期値 0 ではなく、0 要素目という意味
const count = useState[0];
const setCount = useState[1];
ということで、つまり
-
useState
の 0 番目の要素が変数count
に代入される -
useState
の 1 番目の要素が変数setCount
に代入される
と同じ意味になります。
この 2 行分の式を 分割代入 で省略して 1 行で書かれています。
この変数名は任意で問題ありませんが、
- 0 番目の要素の変数名は、state の内容に合った名前を使う(今回は
count
) - 1 番目の要素の変数名は、
set
+ 0 番目の要素名を使う(今回はsetCount
)
とするのが一般的です。
どういう構成をしているのかがわかったので、
useState
の 0 番目の要素と 1 番目の要素がどのような動きをしているか見てきましょう。
- 0 番目の要素(
count
)には、state の値 が代入される - 1 番目の要素(
setCount
)には、state 値を更新する関数 と コンポーネントを再描画させる 役割
となっています
今までの内容をまとめると、
-
count
の初期値が0 -
setCount
関数を呼び出すことでCounter
関数コンポーネントが呼び出されて再描画する -
setCount
の関数で値が変わる毎にcount
の値が更新される -
count
には更新された state の値が代入される
ということになります。
では、今回のソースコードの流れを追っかけてみましょう。
import { useState } from "react";
export const Counter = () => {
// useState フックを使ってクリックの回数をステート管理
const [count, setCount] = useState<number>(0);
return (
<div>
<p>{count} 回クリックしました。</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
下記は、Counter
コンポーネントが呼び出されてからの state の値の流れです。
- 初期値 0 が
count
に代入される - Click me ボタンをクリックすると
setCount
関数呼び出される -
setCount
関数にcount
(最初は初期値 0)が渡され、count + 1
の処理を行う -
Counter
コンポーネントが再度呼び出され描画する -
setCount
関数の引数のcount + 1
がcount
に代入されcount
を更新する - 以降 2 ~ 5 を繰り返す
これで、useState
を使ってクリックすると数字が +1 されるロジックがわかったのではないでしょうか?
このように Hook は、自身がコンポーネントを新しいデータで 再描画する 能力を持っています。
このコンポーネントを再描画させるという Hook の役割をしっかりと理解できていなかったので、
React がチンプンカンプンだったんだなと記事にしてわかりました。
スッキリしました。
5.3.useState の更新関数の引数
先程見てきたソースコードはよろしくない部分があります。
import { useState } from "react";
export const Counter = () => {
// useState フックを使ってクリックの回数をステート管理
const [count, setCount] = useState<number>(0);
return (
<div>
<p>{count} 回クリックしました。</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
それは、setCount
の引数です。
何がいけないかと言いますと、
setCount
の中で現在の state である count
を参照して +1 をしています。
連続でクリックしたときに、タイミングによっては setCount
の更新が完了する前の count
を参照してしまう場合があります。
これを解決するために、setCount
の引数には
setCount((prev) => prev + 1)
と関数を指定すると良いです。
こうすることで、
更新する前の state の値が prev
に渡され、その値に +1 をするため確実に更新することができます。
最終的なソースは以下の通りです。
import { useState } from "react";
export const Counter = () => {
// useState フックを使ってクリックの回数をステート管理
const [count, setCount] = useState<number>(0);
return (
<div>
<p>{count} 回クリックしました。</p>
<button onClick={() => setCount((prev) => prev + 1)}>Click me</button>
</div>
);
}
6.おわりに
分割代入と Hook の自身がコンポーネントを新しいデータで 再描画する という内容を理解すると useState
って難しくないんだなと感じました。
一つ一つの動きを確実に捉えていくことが大切ですね。
横着して、なんとなくの理解で進めてきていたため React って苦手意識を持ってしまっていたんだなと反省しました。
引き続き、Hook 関係の記事を挙げていきますので、見ていただけますと幸いです🙇♂️
併せて他の記事も読んでいただけると嬉しいです🙇♂️
最後まで読んでいただき、ありがとうございました😊
7.参考
-
React ハンズオンラーニング web アプリケーション開発のベストプラクティス
著: Alex Banks, Eve Porcello
訳: 宮崎 空