ReactのPropsとStateでよくあるエラーと解決方法まとめ!初心者向け解説
生徒
「Reactでプログラムを書いていると、PropsやStateに関するエラーがよく出て困ります。どうすればいいですか?」
先生
「Props(プロップス)やState(ステート)はReactの基本ですが、エラーになりやすいポイントがあります。よくある間違いを理解しておけば安心ですよ。」
生徒
「どんなエラーが多いんですか?そして、どう直せばいいんですか?」
先生
「それでは、実際にPropsやStateでよくあるエラーとその解決方法を、具体例と一緒に説明していきましょう!」
1. Propsを直接変更しようとしてエラーになる
Reactでは、Propsは「親コンポーネントから子コンポーネントに渡されるデータ」であり、基本的に読み取り専用の値として扱います。いちど親から渡されたPropsは、子コンポーネント側で書き換えてはいけません。書き換えようとすると、エラーになったり、画面に予想と違う結果が表示されたりします。
イメージとしては、Propsは「親から渡された手紙の内容」のようなものです。ポストから受け取った手紙を勝手に書き換えてしまうと、本来のメッセージが分からなくなってしまいますよね。Reactでも同じで、「内容を変えたいときは親にお願いして、新しい手紙を書き直してもらう」というルールになっています。
function Child(props) {
// ❌ NG: propsの値を直接変更してはいけない
props.message = "変更しました";
return <h1>{props.message}</h1>;
}
Reactの基本的な考え方として、「どの値を表示するか」は親コンポーネントが決めて、子コンポーネントはそれをそのまま受け取って表示するだけ、という役割分担があります。子どもは表示担当、親が値を管理する担当、と覚えておくと分かりやすいです。
そのため、値を変えたいときは、親コンポーネント側でState(ステート)を更新し、その更新された値をPropsとして子コンポーネントに渡すのが正しい流れになります。下のサンプルでは、ボタンをクリックすると親のStateが変わり、その結果として子の表示が変わる様子を確認できます。
import React, { useState } from "react";
function Child(props) {
return <h1>{props.message}</h1>;
}
function App() {
const [message, setMessage] = useState("こんにちは!");
return (
<div>
<Child message={message} />
<button onClick={() => setMessage("変更されました!")}>
メッセージを変更
</button>
</div>
);
}
export default App;
このように、「Propsは読むだけ」「値を変えるのは親コンポーネントのState経由」というルールを意識しておくと、ReactのPropsエラーを避けやすくなります。プログラミングが初めての方は、親子の会話のように「親が内容を決めて、子はそれを素直に伝えるだけ」とイメージしながらコードを読むと理解しやすくなります。
2. Stateを直接書き換えてしまうエラー
StateはReactで「今の状態」を管理するための大切な仕組みです。しかし、このStateに直接代入してしまうと、Reactが変更を認識できず、画面が更新されないという問題が起こります。たとえば、count = count + 1 のように書いてしまうと、一見正しく動きそうに見えても、実際にはReactが変化を追跡できません。
イメージとしては、冷蔵庫に新しい食材を入れたのに、家族が見るレシピノートにその情報を書かないようなものです。冷蔵庫の中は変わっているのに、レシピノートが古いままなので、家族は変化に気づけません。Reactもこれと同じで、「変わったよ」と知らせる専用の方法、つまりsetCountのような更新関数を使う必要があります。
import React, { useState } from "react";
function App() {
const [count, setCount] = useState(0);
// ❌ NG: 直接代入するとReactは気づかない
const wrongUpdate = () => {
count = count + 1;
};
// ✅ OK: setCountを使って更新する
const correctUpdate = () => {
setCount(count + 1);
};
return (
<div>
<p>現在のカウント: {count}</p>
<button onClick={wrongUpdate}>間違った更新</button>
<button onClick={correctUpdate}>正しい更新</button>
</div>
);
}
export default App;
State更新関数を使うことは、Reactが画面を正しく再描画するための非常に重要なポイントです。特に初心者の方は、「Stateは直接触らず、必ずsetState系の関数を使う」というルールを最初に覚えておくと、エラーを大きく減らせます。Reactがどのように状態を管理しているかを理解するきっかけにもなるので、基本としてしっかり身につけておくと安心です。
3. PropsやStateの初期値がundefinedになる
初心者によくあるエラーが「Cannot read property '〇〇' of undefined」というものです。これは、PropsやStateの初期値を正しく設定していないときに起こります。
たとえば、配列やオブジェクトを使う場合は、最初に空の配列[]や空のオブジェクト{}を指定しておくと安全です。
import React, { useState } from "react";
function App() {
// ❌ NG: 初期値がundefined
// const [user, setUser] = useState();
// ✅ OK: 初期値を空のオブジェクトにする
const [user, setUser] = useState({ name: "", age: 0 });
return (
<div>
<p>名前: {user.name}</p>
<p>年齢: {user.age}</p>
</div>
);
}
export default App;
4. PropsやStateの非同期更新で値がずれる
Stateの更新は非同期で行われることが多いため、すぐに新しい値を使おうとするとずれてしまうことがあります。解決方法は、更新関数に「前の値」を渡して計算する方法です。
import React, { useState } from "react";
function App() {
const [count, setCount] = useState(0);
// ❌ NG: 古い値を参照してしまうことがある
const wrongIncrement = () => {
setCount(count + 1);
setCount(count + 1);
};
// ✅ OK: 関数型の更新を使う
const correctIncrement = () => {
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
};
return (
<div>
<p>現在のカウント: {count}</p>
<button onClick={wrongIncrement}>間違った加算</button>
<button onClick={correctIncrement}>正しい加算</button>
</div>
);
}
export default App;
5. Propsの型が合わないときのエラー
親コンポーネントから渡すPropsの型(文字列・数値など)が違うと、意図しない表示やエラーが発生することがあります。例えば、数値を文字列として扱ってしまうなどです。
解決策は、渡す値の型を確認することや、PropTypesやTypeScriptを使って型を明示することです。
import React from "react";
import PropTypes from "prop-types";
function Child(props) {
return <h1>年齢: {props.age}</h1>;
}
Child.propTypes = {
age: PropTypes.number.isRequired,
};
export default Child;
まとめ
この記事では、ReactのPropsとStateでよく起こるエラーとその解決方法を初心者向けに解説しました。Propsは親から子に渡される読み取り専用のデータであり、直接変更するとエラーになります。一方、Stateはコンポーネントが管理するデータで、必ず更新関数(set関数)を通じて変更しなければ、Reactが変化を検知できず画面が更新されません。また、StateやPropsの初期値が未設定だとundefinedによるエラーが発生したり、非同期更新のタイミングで値がずれることもあります。これらの問題は、初期値の設定や関数型の更新、型のチェックを行うことで解決できます。
さらに、PropsとStateを組み合わせることで、ログイン状態の切り替えやフォーム入力のリアルタイム反映など、より実用的でインタラクティブなReactアプリを作ることができます。Propsはデータや関数を子コンポーネントに渡す役割、Stateはそのコンポーネント内部でデータを管理し変化を反映させる役割を持つことを理解すれば、エラーを防ぎつつ効率的に開発できます。
初心者の方は、Propsは「親からもらうプレゼント」、Stateは「自分のノート」と考え、Stateは必ず更新関数を使って変更する、Propsは読み取り専用で変更しない、初期値を設定する、非同期更新では前の値を参照する、といったルールを押さえておくと、Reactでのデータ管理がスムーズに行えます。PropTypesやTypeScriptで型を明示することも、予期せぬエラーを防ぐ重要なポイントです。
import React, { useState } from "react";
import PropTypes from "prop-types";
function Child({ age }) {
return <h1>年齢: {age}</h1>;
}
Child.propTypes = {
age: PropTypes.number.isRequired,
};
function App() {
const [count, setCount] = useState(0);
const [isLogin, setIsLogin] = useState(false);
const increment = () => {
setCount((prev) => prev + 1);
};
return (
<div>
{isLogin ? <Child age={count} /> : <p>ログインしてください</p>}
<button onClick={() => setIsLogin(!isLogin)}>
{isLogin ? "ログアウト" : "ログイン"}
</button>
<button onClick={increment}>カウントを増やす</button>
</div>
);
}
export default App;
生徒
「Propsは読み取り専用、Stateは更新関数で管理するもの、という基本ルールが理解できました。」
先生
「その通りです。これを守ることで、Reactのコンポーネントが正しく画面を更新し、エラーも防げます。」
生徒
「初期値を設定したり、非同期更新では前の値を参照する方法も覚えました。」
先生
「はい。PropsとStateの違いを意識しながら、安全に更新することがReact開発の基本です。型チェックも活用すると、さらに安心ですね。」
生徒
「これで、よくあるPropsやStateのエラーを防ぎつつ、実用的なアプリを作れる気がします!」
先生
「その意気です。まずは小さなアプリで復習し、PropsとStateの使い方に慣れていきましょう。」