【解決】Cannot read properties of undefined/null エラーの原因と修正
ReactでよくあるCannot read properties of undefinedエラーを解説。非同期データの読み込み前アクセス・undefinedなpropsなど原因別に修正方法を示します。
制作・運営:React Guide 運営者
このエラーを見たとき、「ちゃんとfetchしてるのになんでnullなんだ」という気持ちになりやすい。
TypeError: Cannot read properties of undefined (reading 'name')
TypeError: Cannot read properties of null (reading 'map')コードを直す前に、なぜこのエラーが起きるのかを理解しておいたほうがいい。原因がわかると、次に同じミスをしなくなるからだ。
初期値がnullで、Effectから取得する場合
初めてReactを書いたとき、こういう順番で動くと思いやすい。
useEffectでfetchする → データが届く → 画面に表示される実際の流れはこうだ。
① コンポーネントが実行される(userはまだnull)
② JSXを計算する(ここで例外なら以降へ進めない)
nullを扱えればコミットする
③ useEffectが走り始める
④ fetchが始まる(ネットワーク通信が走る)
⑤ データが届く
⑥ setUser(data) → ①に戻って再描画
⑦ 今度はuserに値があるので正しく表示されるEffectはコミット後に実行されます。この例では初期値がnullなので、最初のレンダーでnullを扱う必要があります。そこで例外を投げるとコミットできず、Effectによる取得にも進みません。SSRやルートのloaderで事前に取得する構成は、この順序とは異なります。
このしくみを知っていれば、エラーの読み方が変わる。「nullのプロパティにアクセスした」ではなく、「データが届く前に描画が走った」という話だとわかる。
原因1:非同期データがまだ届いていない
上の流れを踏まえてコードを見ると、エラーの理由がわかる。
// ❌ なぜ失敗するのか
function UserProfile({ userId }: { userId: number }) {
const [user, setUser] = useState(null) // 初期値はnull
useEffect(() => {
fetchUser(userId).then(setUser) // これは描画の後に走る
}, [userId])
return <div>{user.name}</div> // 最初の描画でnull.nameを参照 → エラー
}「fetchしてるのになんでnullなんだ」ではなく「fetchが終わる前に描画が走っている」という話だ。
修正は、「データがない間は別の表示をする」こと。
// ✅ データが届くまでの表示を用意する
function UserProfile({ userId }: { userId: number }) {
const [user, setUser] = useState<User | null>(null)
useEffect(() => {
fetchUser(userId).then(setUser)
}, [userId])
if (!user) return <div>読み込み中...</div> // データがない間はここで止まる
return <div>{user.name}</div> // ここに来たとき、userは必ず存在する
}if (!user) return のパターンは「早期リターン」と呼ばれる。useEffectでデータ取得するコンポーネントではほぼ毎回登場する書き方なので、定番として覚えておいていい。
原因2:配列が undefined のまま .map() を呼んでいる
同じ「存在しないかもしれない値」の問題が、配列で起きるパターン。
// ❌ items が省略されたとき、.map() が存在しないのでエラー
function ItemList({ items }: { items?: string[] }) {
return (
<ul>
{items.map((item) => <li>{item}</li>)}
</ul>
)
}? がついているということは「渡されないこともある」ということだ。渡されなかったとき items は undefined で、undefined.map() は存在しない。
修正の方法は2つある。
// ✅ パターン1:「必ず配列として受け取る」ようにデフォルト値を設定する
function ItemList({ items = [] }: { items?: string[] }) {
return (
<ul>
{items.map((item, i) => <li key={i}>{item}</li>)}
</ul>
)
}// ✅ パターン2:オプショナルチェーンで「undefinedなら何もしない」
function ItemList({ items }: { items?: string[] }) {
return (
<ul>
{items?.map((item, i) => <li key={i}>{item}</li>)}
</ul>
)
}パターン1は「コンポーネントの中では配列として扱える」保証があるので、その後の処理がシンプルになる。パターン2は undefined のまま外に持ち出せるが、undefined のときは何も表示されない。どちらが正解かは要件次第だが、配列を描画するコンポーネントではパターン1のほうが見通しが良くなることが多い。
原因3:オブジェクトの途中がundefined
APIレスポンスで order.customer.address.city のように深い構造にアクセスするとき、途中が undefined だとエラーになる。
// ❌ customer が optional なのに直接 .name を参照している
type Order = {
id: number
customer?: { name: string; address?: { city: string } }
}
function OrderSummary({ order }: { order: Order }) {
return (
<div>
<p>{order.customer.name}</p> {/* customerがなければエラー */}
<p>{order.customer.address.city}</p> {/* addressがなければエラー */}
</div>
)
}「customerが来ないはずがない」と思っていても、APIにnullが含まれたり、必要なプロパティが欠けていたりすることがある(JSONにundefinedという値はない)。
オプショナルチェーン(?.)を使うと、途中が undefined ならそこで処理が止まって undefined を返す。エラーにならない。
// ✅ 途中がundefinedでもクラッシュしない
function OrderSummary({ order }: { order: Order }) {
return (
<div>
<p>{order.customer?.name ?? '未設定'}</p>
<p>{order.customer?.address?.city ?? '未設定'}</p>
</div>
)
}?.(オプショナルチェーン)と ??(nullish coalescing)はセットで使うことが多い。「undefinedかもしれないが、そのときはこの値を使う」という意図が一行で書ける。
原因4:useRefのcurrentにマウント前にアクセスしている
useRef でDOM要素を操作するとき、同じ「タイミング」の問題が起きる。
// ❌ コンポーネントの実行中はまだDOMが存在しない
function InputWithFocus() {
const inputRef = useRef<HTMLInputElement>(null)
inputRef.current.focus() // null.focus() → エラー
return <input ref={inputRef} />
}refにDOM要素がセットされるのは、Reactが画面を描いた後だ。returnの前(コンポーネントが実行されている最中)はまだ current が null のまま。
原因1と同じ構造だ。「描く前にアクセスしようとしている」。
// ✅ useEffectの中(描画後)で操作する
function InputWithFocus() {
const inputRef = useRef<HTMLInputElement>(null)
useEffect(() => {
inputRef.current?.focus() // 描画後に実行されるので安全
}, [])
return <input ref={inputRef} />
}TypeScriptで事前に気づく
tsconfig.json の strict: true を有効にしておくと、TypeScriptが「ここはnullかもしれない」と書いている時点で教えてくれる。
{
"compilerOptions": {
"strict": true
}
}このエラーで画面が真っ白になって原因を探すより、エディタ上で赤線を見つけるほうがずっと早い。TypeScriptの警告が出たとき「うるさい」と感じる場面もあるが、Cannot read properties 系のエラーは型を正しく定義していればTypeScriptで事前に見つけられるものなので、警告を無視しないほうがいい。
このエラーを防ぐ1つの考え方
「データは遅れて来る」という前提で書く。
useEffectで取得する非同期データも、省略可能なpropsも、useRefで参照するDOMも——「ある瞬間は存在しない」という状態がある。その状態での動作をコードに書いておくことが、このエラーへの根本的な対処だ。
確認してみる
初期値null、空配列、HTTP失敗を別々に試す。optional chainingはデータの形式検証ではないので、必須項目がない場合はエラーとして扱う。
同じテーマの教材
【解決】Reactでpropsがundefinedになる・更新されない原因と対処法
Reactでpropsがundefinedになる・値が変わらない原因を解説。親から正しく渡せていないケース・デフォルト値の設定・オプショナルな型定義・初回レンダリング時の対処まで実例付きで説明します。
propsでデータを渡す:FeatureCardコンポーネントを作る
Reactのpropsの仕組みをTypeScriptの型定義と合わせて解説。コピペから脱してデータを外から受け取るコンポーネントの作り方を学ぶ。
JSXの書き方:HTMLとの違いを知ってヒーローセクションを作る
ReactのJSX構文をHTMLと比較しながら解説。className・{}式・自己終了タグ・フラグメントなど、つまずきやすいポイントを実例で学ぶ。