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を適切に管理できれば、複雑なフォームやデータ構造の管理もスムーズになります。
ぜひ、実際のプロジェクトでも活用してみてください!
コメント