React入門 - 6. stateの使い方

6. stateの使い方

引き続きReactの関数コンポーネントの学習を続けていきましょう。次は状態をもつ関数コンポーネントについて取り上げます。一般的に、関数といえば引数で受け取ったデータを処理して結果を返すものであり、状態には依存しないものです。たとえば次の double 関数は、引数の値を2倍にした値を返します。

function double(value) {
    return value * 2;
}

この double 関数を double(3) のように引数に 3 を指定して呼び出すと、戻り値は必ず 6 になります。関数の状態に依存して結果が 5 になったり、7 になったり、ということはありえません。このように引数だけで結果が決まる関数を純粋関数(pure function) などと呼びます。

厳密には関数呼び出しの副作用がないことも純粋関数の条件の一部です。

Reactの関数コンポーネントに話を戻しましょう。関数コンポーネントは名前の示すとおり、関数で定義されたコンポーネントです。そのため props を使ってデータを引数として、受け取ることはできますが、状態( state )を利用することができない、という制約が以前はありました。そのため、状態に依存するコンポーネント(ステートフルなコンポーネント)を定義する場合は、クラスコンポーネントを作成する必要がありました。

しかし、現在の関数コンポーネントには Hooks という仕組みがサポートされています。Hooks とは関数コンポーネントに状態管理などの様々な機能を追加する仕組みです。この Hooks という仕組みを使うことで関数コンポーネントでも簡単に状態( state )を管理できるようになります。

Reactでは状態を state と呼びます。

useState 関数

それでは実際に状態を持つ関数コンポーネントを定義してみましょう。ここではボタンのクリック回数を表示する Counter コンポーネントを作成してみます。Counter コンポーネントではボタンをクリックした回数を状態( state )として管理します。次のプログラムを src フォルダに Counter.js という名前で作成します。

import { useState } from "react";

function Counter() {
    const [count, setCount] = useState(0);
    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={e => setCount(count + 1)}>increment</button>
        </div>
    )
}

export default Counter;

Counter コンポーネントは関数コンポーネントであるため funciton キーワードで関数を定義しています。また関数の内部ではJSXを使って出力するタグを定義しています。これまでの関数コンポーネントと異なるのは以下の部分です。

    const [count, setCount] = useState(0);

ここではReactに用意されている useState 関数を利用しています。これはステートフック(State Hook)と呼ばれるもので関数コンポーネントに状態を定義する際に利用するものです。

useState 関数は状態管理したいデータを引数で受け取ります。今回は ボタンのクリック回数 を状態として管理したいので、useState 関数の引数に 0 を指定しています。また useState 関数は戻り値で配列を返却します。戻り値となる配列の先頭要素は、現在の状態を表すデータであり、2番目の要素は状態を更新するために関数オブジェクトです。このプログラムの場合、変数 count にクリック回数を代入していて、setCount 変数にクリック回数を更新する関数オブジェクトを代入しています。

useState 関数は react パッケージで定義されています。そのためプログラムの先頭部分で import 宣言を追加しています。import 宣言は手入力せずにテキストエディタの補完機能を使うようにします。

次にJSXの定義を見てみましょう。

        <div>
            <p>Count: {count}</p>
            <button onClick={e => setCount(count + 1)}>increment</button>
        </div>

ここでは <p> タグの中で先ほど useState 関数で取得した変数 count を出力しています。変数 count はクリック回数を表す状態( state )です。初期値は 0 ですが後の increment ボタンがクリックされるたびに状態が更新されて、出力が変化します。次に <button> タグの定義部分では onClick プロパティにイベントハンドラを無名関数で定義しています。

            <button onClick={e => setCount(count + 1)}>increment</button>

onClickプロパティには、イベントオブジェクト(上記の変数 e )を引数にとる関数を指定できます。ここで定義した関数では、 先の useState 関数の戻り値である setCount 関数を使って状態(クリック回数)をインクリメントしています。

Reactの state の更新は必ず専用の関数(この場合、setCount )を使う必要があります。count 変数を直接更新するのではない、という点に注意していください。

App.js

つづいて作成した Counter コンポーネントを親コンポーネントである App.js に追加してみましょう。

import './App.css';
import Counter from './Counter';
import Hello from './Hello';

function App() {
  return (
    <>
      <Hello name="React" />
      <Counter />
    </>
  );
}

export default App;

ここでは Hello コンポーネント定義のあとに Counter コンポーネントを追記しています。またReactの関数コンポーネントは必ず1つのルートコンポーネントを持つ必要があるため、ここではフラグメント <></>を宣言しています。

    <>
      <Hello name="React" />
      <Counter />
    </>

もしフラグメントを使わずに以下のように関数コンポーネントを定義すると、コンパイラはエラーを検出します。

function App() {
  return (
      <Hello name="React" />
      <Counter />
  );
}

このようにコンポーネント定義時にはいくつかの制約にしたがう必要があります。

動作確認

それではブラウザからアクセスして動作を確認しておきましょう。 npm start によって開発サーバを起動した状態で、ブラウザを開いて http://localhost:3000 にアクセスすると次のような結果を確認できるでしょう。

上記のように <Hello name="React" /> コンポーネントの出力の後に <Counter /> コンポーネントの出力結果を確認できるでしょう。また表示された increment ボタンをクリックすると数値が加算されていく様子を確認できます。

実行結果から Counter コンポーネントがボタンをクリックした回数を状態( state )として管理できていることがわかります。

関数コンポーネントとHooks

Reactには class を使ったコンポーネントの定義方法(クラスコンポーネント)と、function を使ったコンポーネントの定義方法(関数コンポーネント)の2つが用意されています。2022.3月現在においてはクラスベースでもコンポーネントも定義できますが、関数コンポーネントを使うことが主流になってきています。その理由は関数コンポーネントに Hooks という仕組みが導入されたからです。

関数コンポーネントにはReactの Hooks という仕組みを利用することで、 useState 関数で状態管理機能を追加できることを学びました。Hooks には状態管理機能を追加する以外にも、コンポーネントの副作用(データの取得処理など)を定義する useEffect といった関数も用意されています。これらの機能を必要に応じて、コンポーネントにフックする(ひっかける)ことで、クラスベースのコンポーネントと同様の機能を使って開発を進めることができます。

2022.3月時点時点では、一部の機能はクラスベースでしか扱えないものあるようです。

まとめ

本講座ではNode.jsのインストールから create-react-app によるReactプロジェクトの作成方法、それからコンポーネントの作成方法について解説しました。

Reactはユーザインタフェースを構築するライブラリです。関数コンポーネントやJSXのような仕組みを使って画面を構成するコンポーネントを宣言的に定義します。宣言的に定義されたReactのコンポーネントは状態の変化を検出すると自動的に画面を再描画します。Reactのコンポーネントは親コンポーネントから子コンポーネントへデータを受け渡すために propsを使います。またコンポーネント内で状態を管理するために state を使います。まずはコンポーネントの基本的な仕組みである propsstate の使い方に慣れていくことがReact学習のポイントになります。