React で「Objects are not valid as a React child」が解消できない
JSX の中括弧にオブジェクトや配列内オブジェクト、Promise、Date などを直接置くと React は描画できずこのエラーを投げる。
表示したい文字列や数値、React 要素に変換してから埋め込むのが基本。
#react#jsx#rendering#error#children
要約
Objects are not valid as a React child (found: object with keys {...}) は、JSX の {} にそのままオブジェクトを置いた ときに出る。
React が描画できるのは文字列・数値・React 要素・配列などで、プレーンオブジェクトや Promise、Date インスタンスは直接レンダリングできない。
エラーメッセージの with keys {...} 部分が、混入したオブジェクトの形を教えてくれる。
よくある原因
- オブジェクトを直接埋め込み:
{user}と書いてしまう(正しくは{user.name}) - 配列要素がオブジェクト:
{items}で配列の中のオブジェクトがそのまま展開される - Promise を埋め込み:
{fetchUser()}のように非同期関数の戻り値(Promise)を置いている - Date / クラスインスタンス:
{new Date()}や独自クラスを文字列化せず描画している
解決策
1. プロパティを取り出す
// NG
return <p>{user}</p>;
// OK
return <p>{user.name}</p>;エラーの found: object with keys {name, age} を見れば、どのオブジェクトが入り込んだか特定できる。
2. 配列は map で要素化する
{items.map(item => (
<li key={item.id}>{item.label}</li>
))}配列をそのまま置くと中身のオブジェクトが描画対象になる。公式のリスト描画ガイド のとおり map で React 要素に変換し、key を付ける。
3. 非同期データは state 経由で
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser().then(setUser);
}, []);
return <p>{user?.name ?? "読み込み中"}</p>;{fetchUser()} は Promise を描画しようとして失敗する。
解決済みの値を state に入れてから描画する。
4. オブジェクトは明示的に文字列化
<pre>{JSON.stringify(data, null, 2)}</pre>
<span>{date.toLocaleString()}</span>デバッグ目的なら JSON.stringify、表示目的なら必要なプロパティだけを文字列として渡す。
JSX の {} に書けるのは式の評価結果が描画可能な値の場合だけ、という原則は 公式の JSX ガイド にある。