v19.2Latest

State: コンポーネントのメモリ

コンポーネントは、インタラクションの結果として画面上の表示を変更する必要がよくあります。フォームへの入力は入力フィールドを更新し、画像カルーセルの「次へ」をクリックすると表示される画像が変わり、「購入」をクリックすると商品がショッピングカートに入ります。コンポーネントは、現在の入力値、現在の画像、ショッピングカートといったものを「記憶」する必要があります。Reactでは、この種のコンポーネント固有のメモリをstateと呼びます。

学習内容
  • useStateフックで状態変数を追加する方法
  • useStateフックが返す値のペア
  • 複数の状態変数を追加する方法
  • stateがローカルと呼ばれる理由

通常の変数では不十分な場合

以下は彫刻の画像をレンダリングするコンポーネントです。「次へ」ボタンをクリックすると、index1、次に2と変更して次の彫刻を表示するはずです。しかし、これは動作しません(試してみてください!):

handleClickイベントハンドラはローカル変数indexを更新しています。しかし、その変更が反映されない理由が2つあります:

  1. ローカル変数はレンダー間で保持されない。Reactがこのコンポーネントを2回目にレンダーするとき、最初からレンダーします。ローカル変数の変更は考慮されません。
  2. ローカル変数の変更はレンダーをトリガーしない。Reactは、新しいデータでコンポーネントを再度レンダーする必要があることを認識しません。

新しいデータでコンポーネントを更新するには、2つのことが起こる必要があります:

  1. 保持レンダリング間のデータ。
  2. トリガーReactが新しいデータでコンポーネントをレンダリングする(再レンダリング)。

useStateフックはこれら2つを提供します:

  1. ステート変数レンダリング間のデータを保持するため。
  2. ステートセッター関数変数を更新し、Reactにコンポーネントの再レンダリングをトリガーするため。

ステート変数の追加

ステート変数を追加するには、ファイルの先頭でReactからuseStateをインポートします:

次に、この行を置き換えます:

以下のように

indexはステート変数であり、setIndexはセッター関数です。

[]の構文は配列の分割代入と呼ばれ、配列から値を読み取ることができます。useStateが返す配列には常にちょうど2つの項目があります。

これらがhandleClick内でどのように連携するか:

これで「次へ」ボタンをクリックすると、現在の彫刻が切り替わります:

最初のフックに出会う

Reactでは、useStateや「use」で始まる他の関数は、フックと呼ばれます。

フックは、Reactがレンダリング中のときだけ利用可能な特別な関数です(詳細は次のページで説明します)。これらを使うと、さまざまなReactの機能に「フック(接続)」できます。

Stateはそのような機能の一つに過ぎませんが、他のフックについては後で説明します。

落とし穴

フック(useで始まる関数)は、コンポーネントのトップレベルまたは独自のフックのトップレベルでのみ呼び出すことができます。条件文、ループ、その他のネストされた関数内でフックを呼び出すことはできません。フックは関数ですが、コンポーネントが必要とするものについての無条件の宣言と考えると理解しやすいでしょう。ファイルの先頭でモジュールを「インポート」するのと同様に、コンポーネントの先頭でReactの機能を「使用」します。

useStateの構造

あなたがuseStateを呼び出すとき、このコンポーネントに何かを記憶させたいとReactに伝えています:

この場合、Reactにindexを記憶させたいのです。

注記

このペアはconst [something, setSomething]のように命名するのが慣例です。好きな名前を付けることもできますが、慣例に従うことでプロジェクト間での理解が容易になります。

useStateの唯一の引数は、状態変数の初期値です。この例では、indexの初期値は0に設定されており、useState(0)で指定されています。

コンポーネントがレンダリングされるたびに、useStateは2つの値を含む配列を返します:

  1. 保存した値を持つstate変数(index)。
  2. state変数を更新し、Reactにコンポーネントの再レンダーをトリガーするstateセッター関数(setIndex)。

実際の動作は以下の通りです:

  1. コンポーネントが初めてレンダリングされます。 0useStateindexの初期値として渡したため、[0, setIndex]が返されます。Reactは0が最新のstate値であることを記憶します。
  2. stateを更新します。ユーザーがボタンをクリックすると、setIndex(index + 1)が呼び出されます。index0なので、setIndex(1)となります。これにより、Reactはindex1になったことを記憶し、別のレンダーをトリガーします。
  3. コンポーネントの2回目のレンダリング。Reactは依然としてuseState(0)を見ていますが、Reactは記憶しているため、index1に設定したことを覚えており、代わりに[1, setIndex]を返します。
  4. 以降も同様です!

コンポーネントに複数のstate変数を与える

1つのコンポーネント内に、好きなだけ多くの種類のstate変数を持つことができます。このコンポーネントには、数値のindexと、ブール値のshowMoreという2つのstate変数があり、「詳細を表示」をクリックすると切り替わります:

状態が無関係である場合、例えばこの例の indexshowMoreのように、複数の状態変数を持つことは良い考えです。しかし、2つの状態変数を頻繁に一緒に変更する場合は、それらを1つにまとめた方が簡単かもしれません。例えば、多くのフィールドを持つフォームの場合、フィールドごとに状態変数を持つよりも、オブジェクトを保持する単一の状態変数を持つ方が便利です。詳細なヒントについては、状態構造の選択をお読みください。

Stateは独立しておりプライベートです

Stateは画面上のコンポーネントインスタンスに対してローカルです。言い換えると、同じコンポーネントを2回レンダリングしても、それぞれのコピーは完全に独立したstateを持ちます!一方を変更しても、もう一方には影響しません。

この例では、先ほどのGalleryコンポーネントがロジックを変更せずに2回レンダリングされています。各ギャラリー内のボタンをクリックしてみてください。それらのstateが独立していることに注目してください:

これが、モジュールのトップで宣言する通常の変数と状態の違いです。状態は特定の関数呼び出しやコード内の場所に結び付けられているのではなく、画面上の特定の場所に対して「ローカル」です。2つの<Gallery />コンポーネントをレンダリングしたので、それらの状態は別々に保存されます。

また、PageコンポーネントがGalleryの状態について何も「知らない」こと、あるいは状態を持っているかどうかさえ知らないことに注目してください。propsとは異なり、状態はそれを宣言するコンポーネントに対して完全にプライベートです。親コンポーネントはそれを変更できません。これにより、他のコンポーネントに影響を与えることなく、任意のコンポーネントに状態を追加したり削除したりできます。

両方のギャラリーの状態を同期させたい場合はどうすればよいでしょうか?Reactでこれを行う正しい方法は、子コンポーネントから状態を削除し、それらが共有する最も近い親コンポーネントに追加することです。次の数ページでは、単一コンポーネントの状態の整理に焦点を当てますが、このトピックについてはで再び取り上げます。コンポーネント間での状態の共有

まとめ

  • コンポーネントがレンダー間で情報を「記憶」する必要がある場合、状態変数を使用します。
  • 状態変数は、useStateフックを呼び出すことで宣言されます。
  • フックは、useで始まる特別な関数です。これらを使用すると、状態のようなReactの機能に「フック(接続)」できます。
  • フックはインポートを連想させるかもしれません:それらは無条件に呼び出される必要があります。フック(useStateを含む)の呼び出しは、コンポーネントまたは別のフックのトップレベルでのみ有効です。
  • useStateフックは、現在の状態とそれを更新する関数のペアを返します。
  • 複数の状態変数を持つことができます。内部的には、Reactはそれらの順序によって対応付けます。
  • 状態はコンポーネントに対してプライベートです。2つの場所でレンダリングした場合、各コピーは独自の状態を持ちます。

Try out some challenges

When you press “Next” on the last sculpture, the code crashes. Fix the logic to prevent the crash. You may do this by adding extra logic to event handler or by disabling the button when the action is not possible.

After fixing the crash, add a “Previous” button that shows the previous sculpture. It shouldn’t crash on the first sculpture.


State:コンポーネントのメモリ | React Learn - Reflow Hub