ReactのuseStateでオブジェクトのネストを適切に管理する

基礎

Reactで状態(State)を管理する際、useState フックを使うことが一般的です。

しかし、フォームやAPIデータを扱う場合、一つのStateがオブジェクトとしてネストされることがあります。

例えば、ユーザー情報を管理する場合、以下のようなデータ構造になることがよくあります。

const [user, setUser] = useState({
    name: "田中 太郎",
    age: 20,
    address: {
        country: "日本",
        city: "東京"
    }
});

このように、オブジェクトの中に別のオブジェクト(address)がネストされている場合、Stateの更新方法に少し工夫が必要です。

本記事では、

「ReactのuseStateでオブジェクトのネストを適切に管理する」

と題して、ネストされたStateを適切に管理する方法 を、具体的なコード例を交えながら解説します。

コンポーネントの作成

今回は、以下のフォルダ構成になるように

  • componentsフォルダ
  • NestStateコンポーネント

を作成しておきます!

my-react-app/
├── index.html                     # アプリのエントリーポイント
├── src/                           # ソースコードを格納するディレクトリ
│   ├── components/                ### 今回作成 ###
│   │   └── NestState.jsx          ### 今回作成 ###
│   ├── App.jsx                    # メインコンポーネントTypeScript形式
│   └── main.jsx                   # ReactDOMをレンダリングするエントリーポイント
├── package.json                   # プロジェクトの依存関係とスクリプト
├── tsconfig.json                  # TypeScriptの設定ファイル
└── vite.config.js                 # Viteの設定ファイル

サンプルコード

では、ReactのuseStateでサンプルフォームを実装するためにコードを書いていきます!

ゆーや
ゆーや

詳しいコードの解説は、ページの下の方にあるよ!
しっかり理解したい方は、解説も読んでいただければと思います!

NestState.jsx

import { useState } from "react";

const NestState = () => {
    // 状態を管理するためのuseStateフック
    const [nestForm, setNestForm] = useState({
        name: '田中 太郎',
        age: 20,
        from: {
            country: '日本',
            city: '東京'
        }
    });

    // フォームの入力変更を処理する関数
    const handleChange = (e) => {
        const { name, value } = e.target;
        setNestForm(prevState => ({
            ...prevState,
            [name]: value
        }));
    };

    // ネストされたオブジェクト(from)を更新する関数
    const handleNestedChange = (e) => {
        const { name, value } = e.target;
        setNestForm(prevState => ({
            ...prevState,
            from: {
                ...prevState.from,
                [name]: value
            }
        }));
    };

    // 送信ボタン押下でコンソールに出力
    const submit = () => {
        console.log(nestForm.name);
        console.log(nestForm.age);
        console.log(nestForm.from.country);
        console.log(nestForm.from.city);
    };

    return (
        <div>
            <h2>入力フォーム</h2>
            <form>
                {/* 名前の入力フィールド */}
                <label>
                    名前: <input type="text" name="name" value={nestForm.name} onChange={handleChange} />
                </label>
                <br />
                {/* 年齢の入力フィールド */}
                <label>
                    年齢: <input type="number" name="age" value={nestForm.age} onChange={handleChange} />
                </label>
                <br />
                {/* 国の入力フィールド(ネストされたオブジェクト) */}
                <label>
                    国: <input type="text" name="country" value={nestForm.from.country} onChange={handleNestedChange} />
                </label>
                <br />
                {/* 都市の入力フィールド(ネストされたオブジェクト) */}
                <label>
                    都市: <input type="text" name="city" value={nestForm.from.city} onChange={handleNestedChange} />
                </label>
                <br />
                <button type="button" onClick={submit}>送信</button>
            </form>
            
            {/* 入力内容の表示 */}
            <h3>入力内容</h3>
            <p>名前: {nestForm.name}</p>
            <p>年齢: {nestForm.age}</p>
            <p>国: {nestForm.from.country}</p>
            <p>都市: {nestForm.from.city}</p>
        </div>
    );
};

export default NestState;
ゆーや
ゆーや

今回は、以下のような機能を付けました!

① ネストされたオブジェクト(State)とフォームの値の管理
② Stateの状態をリアルタイムで表示
③ ラジオボタンによる入力値の管理
④ チェックボックスによる入力値の管理
⑤ テキストエリアによる入力値の管理
⑥ 送信ボタン押下時にコンソールに出力

main.jsx

import { createRoot } from 'react-dom/client'
import NestState from './components/NestState'

createRoot(document.getElementById('root')).render(
  <NestState/>
)
ゆーや
ゆーや

main.jsxでは、作成したNestStateをインポートして出力していきます!

実行結果

初期表示

各入力欄を操作

ゆーや
ゆーや

リアルタイムで値を取得して、処理を実装したい場合は、こちらの関数を編集してね!

送信ボタン押下

ゆーや
ゆーや

ボタン押下をきっかけに入力値を使用する(ex. DBアクセスなど)場合は、こちらの関数を編集してね!

コード解説

ネストされたオブジェクト型のState定義

const [nestForm, setNestForm] = useState({
    name: '田中 太郎',
    age: 20,
    from: {
        country: '日本',
        city: '東京'
    }
});
ゆーや
ゆーや

ネストされたオブジェクトの管理は少し工夫が必要だよ!

ネストされたオブジェクトの1層目の状態管理

// フォームの入力変更を処理する関数
const handleChange = (e) => {
    const { name, value } = e.target;
    setNestForm(prevState => ({
        ...prevState,
        [name]: value
    }));
};
ゆーや
ゆーや

1層目のname,ageの値を管理しています!

ネストされたオブジェクトの2層目の状態管理

// ネストされたオブジェクト(from)を更新する関数
    const handleNestedChange = (e) => {
        const { name, value } = e.target;
        setNestForm(prevState => ({
            ...prevState,
            from: {
                ...prevState.from,
                [name]: value
            }
        }));
    };
ゆーや
ゆーや

2層目のfrom.country,from.city の値を管理しています!

送信ボタン押下でコンソール出力

// 送信ボタン押下でコンソールに出力
const submit = () => {
    console.log(nestForm.name);
    console.log(nestForm.age);
    console.log(nestForm.from.country);
    console.log(nestForm.from.city);
};

チェックボックスの入力値の管理

return (
        <div>
            <h2>入力フォーム</h2>
            <form>
                {/* 名前の入力フィールド */}
                <label>
                    名前: <input type="text" name="name" value={nestForm.name} onChange={handleChange} />
                </label>
                <br />
                {/* 年齢の入力フィールド */}
                <label>
                    年齢: <input type="number" name="age" value={nestForm.age} onChange={handleChange} />
                </label>
                <br />
                {/* 国の入力フィールド(ネストされたオブジェクト) */}
                <label>
                    国: <input type="text" name="country" value={nestForm.from.country} onChange={handleNestedChange} />
                </label>
                <br />
                {/* 都市の入力フィールド(ネストされたオブジェクト) */}
                <label>
                    都市: <input type="text" name="city" value={nestForm.from.city} onChange={handleNestedChange} />
                </label>
                <br />
                <button type="button" onClick={submit}>送信</button>
            </form>
            
            {/* 入力内容の表示 */}
            <h3>入力内容</h3>
            <p>名前: {nestForm.name}</p>
            <p>年齢: {nestForm.age}</p>
            <p>国: {nestForm.from.country}</p>
            <p>都市: {nestForm.from.city}</p>
        </div>
    );
ゆーや
ゆーや

2層目の更新用に
国: <input type=”text” name=”country” value={nestForm.from.country}
のように2層目にアクセスするようにしましょう!

まとめ

本記事では

「ReactのuseStateでオブジェクトのネストを適切に管理する」

と題して、ReactのuseStateでネストされたStateを管理する方法 について解説しました。
ポイントを振り返ると、次のようになります。

✅ useState でオブジェクトの状態を管理できる
✅ ネストされたオブジェクトを更新する際は スプレッド構文 (…) を使って上書き する
✅ onChange を適切に設定し、親オブジェクトとネストされたオブジェクトを分けて更新する

ネストされたStateを適切に管理できれば、複雑なフォームやデータ構造の管理もスムーズになります。
ぜひ、実際のプロジェクトでも活用してみてください!

コメント

タイトルとURLをコピーしました