Reactで複数のStateを管理する方法!オブジェクトや配列を使った実践的な使い方
生徒
「先生、ReactでStateを使って値を管理できるのは知ってるんですけど、複数のデータを扱いたいときはどうすればいいんですか?」
先生
「良い質問ですね。ReactではuseStateを使うと一つの値を管理できますが、複数のStateを持ちたいときにはオブジェクトや配列を活用する方法があります。」
生徒
「オブジェクトとか配列って、JavaScriptの基本的なデータの入れ物ですよね?Reactでも使えるんですか?」
先生
「そうです!ReactはJavaScriptをベースにしているので、オブジェクトや配列をStateに入れて使うことができます。では、具体的にコードを見てみましょう。」
1. 複数のStateを管理するには?
ReactではuseStateフックを使うことでコンポーネントごとにデータを保存できます。通常は文字列や数値など1つの値を管理しますが、複数のデータをまとめて扱いたい場合は、オブジェクトや配列をStateに持たせると便利です。オブジェクトは「名前と値のセット」で情報を管理でき、配列は「同じ種類のデータを順番に並べる」イメージです。
例えばユーザーの「名前」と「年齢」をまとめて管理したいときは、オブジェクトを使います。同じように「買い物リスト」や「Todoリスト」など複数の項目を並べて扱いたいときには配列を使います。
2. オブジェクトを使ったState管理
オブジェクトを使えば、複数の関連するデータをひとまとめにして扱えます。次の例では名前と年齢をオブジェクトで管理しています。
import React, { useState } from "react";
function App() {
const [user, setUser] = useState({ name: "太郎", age: 20 });
const updateName = () => {
setUser({ ...user, name: "花子" });
};
const updateAge = () => {
setUser({ ...user, age: user.age + 1 });
};
return (
<div>
<h1>{user.name}({user.age}歳)</h1>
<button onClick={updateName}>名前を変更</button>
<button onClick={updateAge}>年齢を+1</button>
</div>
);
}
export default App;
ここで重要なのは、{...user}という書き方です。これは「スプレッド構文」と呼ばれるもので、元のオブジェクトの中身を展開して、新しい値だけを上書きしています。ReactのStateは直接書き換えるのではなく、新しいオブジェクトを作って渡すのがルールです。
3. 配列を使ったState管理
配列を使うと、複数の同じ種類のデータをまとめて扱えます。例えば「買い物リスト」を管理する場合を見てみましょう。
import React, { useState } from "react";
function App() {
const [items, setItems] = useState(["りんご", "バナナ"]);
const addItem = () => {
setItems([...items, "みかん"]);
};
const removeItem = () => {
setItems(items.slice(0, -1));
};
return (
<div>
<h1>買い物リスト</h1>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
<button onClick={addItem}>みかんを追加</button>
<button onClick={removeItem}>最後を削除</button>
</div>
);
}
export default App;
この例では...itemsを使って既存の配列を展開し、そこに新しい要素を追加しています。削除するときはsliceで配列を切り出しています。このように配列の操作はJavaScriptの基本メソッドを使いながらStateを更新していきます。
4. オブジェクトと配列を組み合わせたState管理
実際のアプリ開発では、オブジェクトと配列を組み合わせて使うケースも多いです。例えば「Todoリスト」を作るときには、配列の中にオブジェクトを入れて、それぞれのタスクに名前や完了フラグを持たせます。
import React, { useState } from "react";
function App() {
const [todos, setTodos] = useState([
{ text: "宿題をする", done: false },
{ text: "部屋を掃除する", done: true },
]);
const toggleTodo = (index) => {
const newTodos = todos.map((todo, i) =>
i === index ? { ...todo, done: !todo.done } : todo
);
setTodos(newTodos);
};
return (
<div>
<h1>Todoリスト</h1>
<ul>
{todos.map((todo, index) => (
<li key={index}>
<span style={{ textDecoration: todo.done ? "line-through" : "none" }}>
{todo.text}
</span>
<button onClick={() => toggleTodo(index)}>完了切替</button>
</li>
))}
</ul>
</div>
);
}
export default App;
ここではmapを使って配列を更新し、特定の要素だけを変更しています。このようにオブジェクトと配列を組み合わせることで、より複雑なデータも効率的に管理できます。
まとめ
複数のStateを扱う考え方を総整理しよう
Reactで複数のStateを管理する方法は、アプリをより豊かに表現するうえで欠かせない重要な考え方です。ひとつの値だけを扱う基本的なState管理から一歩進み、オブジェクトや配列を使うことで多くのデータをまとめて扱えるようになります。今回の記事で紹介したように、ReactのStateはJavaScriptのオブジェクトや配列と非常に相性が良く、実践的なアプリ開発でも頻繁に利用されます。たとえばユーザー情報をひとつのオブジェクトでまとめたり、買い物リストやTodoリストのように複数のデータを配列で管理したりと、柔軟なデータ管理が可能になります。
オブジェクトを使う場面では、スプレッド構文{...user}を使って元のデータを展開しながら一部だけ更新する方法が役立ちます。これはReactのStateが「直接書き換えを禁止している」という性質をもつためで、新しいオブジェクトを渡すことでReactに変更を正しく伝えることができます。同じように、配列を扱う場合でも[...items]を使って既存の配列を展開し、新しい要素を自然な形で追加できます。削除や編集をするときにはsliceやfilter、mapなどのJavaScript標準メソッドを使い、ReactとJavaScriptを組み合わせた柔軟なState更新が行えるようになります。
特に実践的な場面では、配列の中にオブジェクトを入れて管理するパターンがよく見られます。Todoリストの例のように、それぞれの項目に名前や完了状態などの情報を持たせたいときに非常に便利です。mapを使って特定の要素だけを更新し、新しい配列を作り直す流れはReactの代表的な設計であり、この方法を理解すればより複雑なUIにも対応できるようになります。
Reactでは複数のStateを個別に持つこともできますが、データが増えるほどまとまりが悪くなったり、変更箇所が増えて管理が難しくなったりします。そのため、関連するデータはオブジェクトでまとめ、同じ種類のデータは配列で管理する、といった整理されたState構造を意識することはとても大切です。こうすることで、状態の更新が自然に行われ、読みやすく拡張しやすいコードに仕上がります。
さらに、Reactで複数のStateを扱う上で重要なのは「必ず新しい参照のオブジェクトや配列を渡す」という原則です。これはReactが変更を検知するために重要なポイントであり、直接書き換えを避ける習慣が自然に身につけば、状態管理のトラブルも減り、より安定したアプリ開発ができるようになります。
今回の内容を振り返ると、オブジェクトと配列を自由に活用しながらStateを管理する方法は、Reactの基礎を超えて実践に進むためのとても大切なステップです。小さなアプリでも、大規模なアプリでも、この考え方は変わらず活用できるため、しっかり身につけることでReactの理解が一段と深まります。
サンプルコードで復習しよう
記事で解説した内容と同じ構造で、複数のStateを組み合わせる例を次に示します。
import React, { useState } from "react";
function Profile() {
const [info, setInfo] = useState({
name: "佐藤",
age: 22,
hobbies: ["読書", "ジョギング"]
});
const addHobby = () => {
setInfo({ ...info, hobbies: [...info.hobbies, "映画鑑賞"] });
};
const changeName = () => {
setInfo({ ...info, name: "鈴木" });
};
return (
<div class="p-3 border mt-3">
<h2>{info.name}({info.age}歳)</h2>
<ul>
{info.hobbies.map((hobby, index) => (
<li key={index}>{hobby}</li>
))}
</ul>
<button class="btn btn-primary me-2" onClick={addHobby}>
趣味を追加
</button>
<button class="btn btn-secondary" onClick={changeName}>
名前を変更
</button>
</div>
);
}
export default Profile;
このサンプルでは、名前と年齢をオブジェクトで管理しつつ、趣味リストを配列で管理しています。複数のデータ型を組み合わせてStateを管理できる柔軟さは、大規模アプリでも非常に役立つ考え方です。
生徒
「オブジェクトも配列もStateに使えるって知って、Reactがもっと便利に感じました!」
先生
「そのとおりです。特に配列の中にオブジェクトを入れるような構造は実際のアプリでもよく出てきますよ。」
生徒
「スプレッド構文も大事なんですね。直接書き換えちゃうといけない理由もよくわかりました!」
先生
「その感覚が身につけばState管理は安心です。これからもっと複雑な画面も作れるようになりますよ。」
生徒
「今日の学びを使って、Todoアプリも挑戦してみます!」