React で「Objects are not valid as a React child」が解消できない
JSX の中括弧にオブジェクトや配列内オブジェクト、Promise、Date などを直接置くと React は描画できずこのエラーを投げる。
表示したい文字列や数値、React 要素に変換してから埋め込むのが基本。
公開: 更新:
要約
Objects are not valid as a React child (found: object with keys {...}) は、JSX の {} にそのままオブジェクトを置いた ときに出る。
React が描画できるのは文字列・数値・React 要素・配列などで、プレーンオブジェクトや Promise、Date インスタンスは直接レンダリングできない。
エラーメッセージの with keys {...} 部分が、混入したオブジェクトの形を教えてくれる。
実行例
実際に上記の手順を node:20 で動かすと、オブジェクトをそのまま子要素に渡した bad.js は found: object with keys {name, age}、Date インスタンスを渡した bad_date.js は found: [object Date] と、括弧の中に何を渡したかまで書かれた同じ例外で落ちる。
プロパティを取り出し、配列は要素へ展開し、Date と生オブジェクトは文字列に変換した solve_render.js だけが HTML を返して終了コード 0 になる。
$ node bad.js
/tmp/tmp.9Qa6PimEa2/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6995
throw fatalError;
^
Error: Objects are not valid as a React child (found: object with keys {name, age}). If you meant to render a collection of children, use an array instead.
at renderNodeDestructiveImpl (/tmp/tmp.9Qa6PimEa2/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6194:11)
at renderNodeDestructive (/tmp/tmp.9Qa6PimEa2/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6091:14)
... (スタックトレース 8 行省略)
Node.js v20.20.2
$ echo $?
1$ node bad_date.js
/tmp/tmp.9Qa6PimEa2/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6995
throw fatalError;
^
Error: Objects are not valid as a React child (found: [object Date]). If you meant to render a collection of children, use an array instead.
at renderNodeDestructiveImpl (/tmp/tmp.9Qa6PimEa2/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6194:11)
at renderNodeDestructive (/tmp/tmp.9Qa6PimEa2/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6091:14)
... (スタックトレース 8 行省略)
Node.js v20.20.2
$ echo $?
1$ node solve_render.js
<div><p>taro</p><ul><li>a</li><li>b</li></ul><p>1970-01-01T00:00:00.000Z</p><pre>{"name":"taro","age":20}</pre></div>
$ echo $?
0— 2026-08-23 時点の出力
検証環境
- 検証日
- 実行環境
node:20Debian GNU/Linux 12 (bookworm)- バージョン
- Node.js 20.20.2
- npm 10.8.2
- Python 3.11.2
- Git 2.39.5
この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。
よくある原因
- オブジェクトを直接埋め込み:
{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 ガイド(新しいタブで開く) にある。