React HookのuseStateの使い方!複数Stateの管理も!





React HookのuseStateの使い方を知りたいときはないでしょうか。

けど、そんな中で悩むことは、

・React HookのuseStateの使い方がわからない
・React HookのuseStateで複数のStateを管理する方法がわからならい

ですよね。

今回はそんなお悩みを解決する

・React HookのuseStateの使い方
・React HookのuseStateひとつで複数のStateを管理する方法

についてまとめます!

React HookのuseStateのとは

useStateは、React Hookの関数コンポーネントで、コンポーネントの内部保持情報の状態を管理する処理をします。
この内部保持情報の状態のことをReactではstate(ステート)と呼んでいて、useStateはReactのstateを管理する関数ということになります。

具体的にはVDOM(virtual DOM)という仮想のDOMがReact上にあって、さらに変更前と変更後のVDOMにわかれていて、その差分をずうっとみているという処理をしています。

ちょっとわかりづらいですよね…

例えば変数に変化があり、変更前と変更後のVDOMに差分が生じるとReactがその状態を「変更あり!」とキャッチアップし、DOMに出力していくイメージと思ってください。

そもそもDOMとはなんでしょうか。
DOMはDocumentObjectModel(ドキュメント・オブジェクト・モデル)の略でJavascriptでHTMLやCSS,XMLなどドキュメントを管理/操作するインターフェースです。
画面の表示に必要な各ドキュメントがメモリ空間に格納されて必要に応じて加工したり出力していくことをしています。

VDOMは名前は同じですが、こちらはReactコンポーネントで管理、DOMはJavascript本体の管理ということで、オブジェクトとしては分離されています。

なぜオブジェクトを分けているかというと、React上でいったん状態管理し、変更がある場合のみJavascript本体に反映されるということで、DOM単体で管理する場合よりも効率がよいためです。

結果として、画面レンダリングの回数やJavascript本体の処理回数を抑えることができて、よりスピーディーに表示させることができるというわけです。

タカヒロ
タカヒロ
説明だけ聞くとイメージしづらいですね…
アプリケーションが保持しているデータの状態を見ていて、変わったら画面表示も変えてくれるものぐらいに思ってもらえばと思います。

React Hookとは

React Hookについて説明をします。
Hookの意味は釣り針が引っかかる内容となりますので、なにかがきっかけでひかっかって動くようなイメージを覚えておいてください。
React Hookはコンポーネントに再利用可能な動作をつけるために用意された機能です。
これまでコンポーネントをほかでも使いたいといった場合は機能の他にstate(ステート)もクラス継承などで移さなければなりませんでしたが、Hookを使うことにより、このコンポーネントから切り離し、再利用することができます。

タカヒロ
タカヒロ
機能と値があるステートメントを魚(コンポーネント)とすれば、その魚を必要に応じて何度もサクッと釣り上げられるイメージですね。

React HookのuseStateの使い方

React HookのuseStateの使い方について説明をします。

React HookのuseStateの構文と引数

React HookのuseStateの構文と引数は以下の通りです。

React HookのuseStateの構文

const [<第1引数>, <第2引数>] = useState(<初期値>);

React HookのuseStateの引数

第1引数 ステートの値が代入されます。変数からステートの値を得ることができます。
第2引数 ステートの値を変更する関数が入ります。関数の引数に値を指定することによりステートの値を変更することができます。
初期値 初期値を入力します。文字列や数値の他に配列も代入可能です。

タカヒロ
タカヒロ
2つの引数を利用することによりステートの値を操作することが可能というわけですね。
第2引数は関数であることに注意しましょう。

React HookのuseStateを使用して値を表示/変更をする

React HookのuseStateを使用して値を表示/変更していきます。
以下サンプルコードです。

import ReactDOM from 'react-dom'
import React from 'react'
import { useState } from 'react'

const App = () => {
  const [intNum, setCount] = useState('まだない')

  const handleEditFormChange = (e) => {
    setCount(e.target.value)
  }

  return (
    <div>
      <h1> Stateの値は{intNum}です。</h1>
      <input type="text" value={intNum} onChange={handleEditFormChange} />
    </div>
  )
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />)

値を表示する

App.jsなど外部ファイルにコードを記載し、htmlファイルの「<div id=”root”></div>」へ表示させるようにしましょう。

以下のように表示されたら完成です。

値を変更する

次は値を変更してみましょう。

入力ボックスの値を10に設定します。

即時に表示も変わりましたね。

コードの説明

ステートの初期値を’まだない’に設定します。第一引数にintNum、第二引数の関数にsetCountを指定し、第一引数に’まだない’の値が設定されます。

const [intNum, setCount] = useState('まだない')

入力フォームの値が変更されたタイミングで二引数の関数のsetCountを呼び出し、フォームの値をステートに設定します。

  const handleEditFormChange = (e) => {
    setCount(e.target.value)
  }

画面表示用のHTMLです。入力フォームがonChangeになったら「handleEditFormChange」関数を呼び出します。

    <div>
      <h1> Stateの値は{intNum}です。</h1>
      <input type="text" value={intNum} onChange={handleEditFormChange} />
    </div>

React HookのuseStateひとつで複数のStateを管理する方法

React HookのuseStateひとつで複数のStateを管理する方法について説明をします。

例えばステートを複数にした場合は、以下のようにuseStateも複数用意することが考えられます。

const [intNum, setCount] = useState('まだない')
const [intNum2, setCount2] = useState('まだない')
const [intNum3, setCount3] = useState('まだない')

これでは入力フォームがたくさんあった場合はコードもその分記載しなければならず複雑になるのであまりよろしくありません。

そこで以下のように連想配列をuseState引数にしていきます。こうすることで複数の値をまとめてひとつのuseStateへ設定することができます。

  const [intTemp, setCount] = useState({
    intNum1: 'まだない',
    intNum2: 'まだない',
    intNum3: 'まだない'
  })

値変更時のハンドル処理はフォーム分用意します。引数の intTempは配列となるので「 …intTemp, intNum1: e.target.value」のように指定します。

  const handleEditFormChange1 = (e) => {
    setCount({ ...intTemp, intNum1: e.target.value })
  }
  const handleEditFormChange2 = (e) => {
    setCount({ ...intTemp, intNum2: e.target.value })
  }
  const handleEditFormChange3 = (e) => {
    setCount({ ...intTemp, intNum3: e.target.value })
  }

コードをまとめると以下の通りです。

import ReactDOM from 'react-dom'
import React from 'react'
import { useState } from 'react'

const App = () => {
  const [intTemp, setCount] = useState({
    intNum1: 'まだない',
    intNum2: 'まだない',
    intNum3: 'まだない'
  })

  const handleEditFormChange1 = (e) => {
    setCount({ ...intTemp, intNum1: e.target.value })
  }
  const handleEditFormChange2 = (e) => {
    setCount({ ...intTemp, intNum2: e.target.value })
  }
  const handleEditFormChange3 = (e) => {
    setCount({ ...intTemp, intNum3: e.target.value })
  }

  return (
    <div>
      <h2>1つ目のStateの値は{intTemp.intNum1}です。</h2>
      <input
        type="text"
        value={intTemp.intNum1}
        onChange={handleEditFormChange1}
      />
      <h2> 2つ目のStateの値は{intTemp.intNum2}です。</h2>
      <input
        type="text"
        value={intTemp.intNum2}
        onChange={handleEditFormChange2}
      />
      <h2> 3つ目のStateの値は{intTemp.intNum3}です。</h2>
      <input
        type="text"
        value={intTemp.intNum3}
        onChange={handleEditFormChange3}
      />
    </div>
  )
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />)

値を表示する

App.jsなど外部ファイルにコードを記載し、htmlファイルの「<div id=”root”></div>」へ表示させるようにしましょう。

以下のように表示されたら完成です。

値を変更する

次は値を変更してみましょう。

一つ目の入力ボックスから順に10,20,30を入力していきます。

即時に表示も変わりましたね。

複数のハンドル処理を一つにまとめる

前回、入力フォーム値変更時のハンドル処理はフォーム分用意しましたが、フォーム分用意すると複雑になりますので、一つにまとめるようにします。
以下前回のハンドル記述パターンです。

  const handleEditFormChange1 = (e) => {
    setCount({ ...intTemp, intNum1: e.target.value })
  }
  const handleEditFormChange2 = (e) => {
    setCount({ ...intTemp, intNum2: e.target.value })
  }
  const handleEditFormChange3 = (e) => {
    setCount({ ...intTemp, intNum3: e.target.value })
  }

タカヒロ
タカヒロ
フォーム分用意するのはうんざりですよね…

以下ハンドル処理をひとつにまとめたコードです。

import ReactDOM from 'react-dom'
import React from 'react'
import { useState } from 'react'

const App = () => {
  const [intTemp, setCount] = useState({
    intNum1: 'まだない',
    intNum2: 'まだない',
    intNum3: 'まだない'
  })

  const handleEditFormChange = (e) => {
    switch (e.target.name) {
      case 'intNum1':
        setCount({ ...intTemp, intNum1: e.target.value })
        break
      case 'intNum2':
        setCount({ ...intTemp, intNum2: e.target.value })
        break
      case 'intNum3':
        setCount({ ...intTemp, intNum3: e.target.value })
        break
      default:
        console.log('key not found')
    }
  }

  return (
    <div>
      <h2>1つ目のStateの値は{intTemp.intNum1}です。</h2>
      <input
        type="text"
        name="intNum1"
        value={intTemp.intNum1}
        onChange={handleEditFormChange}
      />
      <h2> 2つ目のStateの値は{intTemp.intNum2}です。</h2>
      <input
        type="text"
        name="intNum2"
        value={intTemp.intNum2}
        onChange={handleEditFormChange}
      />
      <h2> 3つ目のStateの値は{intTemp.intNum3}です。</h2>
      <input
        type="text"
        name="intNum3"
        value={intTemp.intNum3}
        onChange={handleEditFormChange}
      />
    </div>
  )
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />)

inputにname属性を追加し、switchによりその値からステート設定処理を分けるようにしています。

値を変更する

同じく値を変更してみましょう。

一つ目の入力ボックスから順に10,20,30を入力していきます。

項目ごとに値が変わりましたね。

タカヒロ
タカヒロ
setCount({ …intTemp, e.target.name: e.target.value })のようにできればswitch不要で1行で済んだのですが、エラーとなりできませんでした。残念…

<追記:改良版>複数のハンドル処理を一つにまとめる

switch不要で1行で済ませる方法がわかりましたので、追記します。
カラム部分に直接変数を代入するとエラーとなりますが、[]でくくることによりエラーを回避し、有効になります。

  const handleEditFormChange = (e) => {
    setCount({ ...intTemp, [e.target.name]: e.target.value })
  }

改良版コードは以下の通りです。

import ReactDOM from 'react-dom'
import React from 'react'
import { useState } from 'react'

const App = () => {
  const [intTemp, setCount] = useState({
    intNum1: 'まだない',
    intNum2: 'まだない',
    intNum3: 'まだない'
  })

  const handleEditFormChange = (e) => {
    setCount({ ...intTemp, [e.target.name]: e.target.value })
  }
  return (
    <div>
      <h2>1つ目のStateの値は{intTemp.intNum1}です。</h2>
      <input
        type="text"
        name="intNum1"
        value={intTemp.intNum1}
        onChange={handleEditFormChange}
      />
      <h2> 2つ目のStateの値は{intTemp.intNum2}です。</h2>
      <input
        type="text"
        name="intNum2"
        value={intTemp.intNum2}
        onChange={handleEditFormChange}
      />
      <h2> 3つ目のStateの値は{intTemp.intNum3}です。</h2>
      <input
        type="text"
        name="intNum3"
        value={intTemp.intNum3}
        onChange={handleEditFormChange}
      />
    </div>
  )
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />)

タカヒロ
タカヒロ
繰り返し分のコードが減った分すっきりしましたね。

動作も問題ありませんね。

さいごに

いかがでしょうか。

今回は、

・React HookのuseStateの使い方
・React HookのuseStateひとつで複数のStateを管理する方法

についてまとめました。

また、他にも便利な方法がありますので、よろしければご参照頂ければと思います。


タカヒロ
タカヒロ
Reactって覚えることが多く難しいですよね...
タカヒロも悩んでいましたが、こちらの本でかなり理解ができるようになりました!


>>Amazonで詳細を見る


電子書籍もいいですが、紙質がやわらかく読みやすいので書籍のほうがおすすめです。


この記事の関連キーワード

こちらの記事の関連キーワード一覧です。クリックするとキーワードに関連する記事一覧が閲覧できます。