コンポーネント間のpropsの受け渡し - React入門

連載目次 : React入門
前回の記事 : React Hooks

React Hooksで追加された機能の中で一番よく利用するのが「useState」です。

これまではコンポーネントを作成する際にClass ComponentではState(状態管理)が利用できましたが、Function ComponentではStateの利用ができず、どちらを利用してコンポーネントを作成するかの判断基準の一つになっていました。

React HooksとuseStateの登場でFunction ComponentでもStateの利用ができるようになりReactのコンポーネントは基本的にはFunction Componentを利用するのが最近の主流となっています。

コンポーネントの作成方法については「コンポーネント – React入門」をClass ComponentでのStateの利用方法については「Stateとは? – React入門」参考にしてください。

基本的な利用方法

読み込み

useStateを利用する場合にはReactのimport時にuseStateを読み込む必要があります。

import React, { useState } from 'react';

状態の定義

そしてFunction Componentのトップレベルの位置で以下の宣言を行い管理する状態変数を作成します。

const [状態変数, 状態変更関数] = useState(状態の初期値);

例えばカウントを管理する変数「count」をFooコンポーネントで利用する場合は以下のように宣言します。

const Foo = () => {
  const [count, changeCount] = useState(0)
  return <p>カウント:{count}</p>
}

useStateを含むReact Hooksの宣言はFunction Componentのトップレベルでしか利用できず以下のような宣言はできませんので注意してください。

const Foo = () => {
  let _count;
  const init = () =>{
    const [count, changeCount] = useState(0)
    _count = count;
  }
  init()
  return <p>カウント:{_count}</p>
}

状態の変更

useStateで定義した状態を変更するには、状態変更関数の引数に新しい状態を入れて実行します。

次のサンプルではボタンがclickされた際にカウントが10になるような状態変更を定義しています。

const Foo = () => {
  const [count, changeCount] = useState(0)
  return (
    <>
      <p>カウント:{count}</p>
      <input
        type="button"
        value="10"
        onClick={() => changeCount(10)}
      />
    </>
  )
}

1づつインクリメントさせたい場合は以下のように定義します。

const Foo = () => {
  const [count, changeCount] = useState(0)
  return (
    <>
      <p>カウント:{count}</p>
      <input
        type="button"
        value="increment"
        onClick={() => changeCount(count+1)}
      />
    </>
  )
}

状態変更関数の引数には新しい状態だけではなく無名関数を指定することができます。

無名関数の引数には直前の状態が引き渡されるので先程の記述は以下のように変更することもできます。

const Foo = () => {
  const [count, changeCount] = useState(0)
  return (
    <>
      <p>カウント:{count}</p>
      <input
        type="button"
        value="increment"
        onClick={() => changeCount(prevCount => prevCount+1)}
      />
    </>
  )
}

Stateの分割管理

これまでClass Componentを利用していた人は複数の状態を1つのuseStateで管理しそうになりますがこれは推奨される方法ではありません。

次のサンプルでは状態変数「state」としてカウントと名前を管理するオブジェクトを定義しておき更新時にそれぞれを更新しています。

const Foo = () => {
  const [state, changeState] = useState({
    count:0,
    name:""
  })
  return (
    <>
      <p>カウント:{state.count}</p>
      <p>名前:{state.name}</p>
      <input
        type="button"
        value="increment"
        onClick={() => changeState(prevState => ({
          ...prevState,
          count:prevState.count+1
        }))}
      />
      <input
        type="text"
        value={state.name}
        onChange={e => changeState(prevState => ({
          ...prevState,
          name:e.target.value
        }))}
      />
    </>
  )
}

ちゃんと動作はするのですが内部的にはカウントの変更時にカウントだけではなく名前の状態も、名前の変更時にはカウントの情報も変更されます。

変更対象だけを更新していたClass ComponentのsetStateとの大きな違いになります。

そのため関連性のない状態は極力別のuseStateで管理するのが望ましいとされています。

先程定義したcountとnameを別のuseStateで管理すると以下のようになります。更新対象の制限だけでなくコード自体の可読性も向上しているでしょう。

const Foo = () => {
  const [count, changeCount] = useState(0)
  const [name, changeName] = useState("")
  return (
    <>
      <p>カウント:{count}</p>
      <p>名前:{name}</p>
      <input
        type="button"
        value="increment"
        onClick={() => changeCount(prevState => prevState+1)}
      />
      <input
        type="text"
        value={name}
        onChange={e => changeName(e.target.value)}
      />
    </>
  )
}

ソースコード/動作サンプル

useStateを利用する場合には細かく状態を管理するように心がけるようにしてください。

次回はReact HooksのuseEffectについて解説を行います。

次回の記事 : useEffect – React Hooks