본문 바로가기
Frontend

[ React ] Cannot read properties of null (reading 'map') 오류 원인 및 해결 방법

by 알기 쉬운 코딩 사전 2024. 10. 14.
반응형

💥 Chrome 개발자 도구에서 발생한 에러 메시지

Uncaught TypeError: Cannot read properties of null (reading 'map')

 

❓에러 발생 이유

현재의 오류 메시지는 null 타입의 변수를 대상으로 map 메서드를 사용했을 때 나타나는 오류 메시지입니다.

 

👉 React의 렌더링 흐름

아래 코드에서 console.log를 통하여 users를 출력해 보겠습니다.

import React, { useEffect, useState } from "react";

function UserPage() {
  const [users, setUsers] = useState(null);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((response) => response.json())
      .then((users) => setUsers(users))
      .catch((error) => console.error("Error fetching users:", error));
  }, []);

  console.log("users : ", users);

  return (
    <div>
      {users.map((user) => (
        <li key={user.id}>{user.username}</li>
      ))}
    </div>
  );
}

export default UserPage;

 
우리가 기대한 users의 값은 Array 타입의 데이터입니다.
하지만 users의 값이 null인 걸 아래 이미지에서 확인할 수 있습니다.

 
그러한 이유는 React의 초기 렌더링 단계에서 API 호출을 진행하였지만, JS의 비동기 처리 특성 때문에
API 호출이 정상적으로 완료되기 전에 렌더링이 완료되어 users의 값이 변경되지 못하여 나타나는 현상입니다.
아래 그림을 참고해 주세요.
 

❌ 오류 상황

1. 초기 렌더링

리액트는 초기 렌더링 시에 users 변수에 초깃값을 null로 설정합니다. 동시에 비동기 API 호출을 시작합니다.
 

2. 렌더링 완료

하지만 API는 호출 중인 상태에서는 users 값이 초깃값인 상태입니다.

그러니 users의 값은 null이며 이 상태에서 렌더링을 완료 시켜서 에러가 발생하게 되는 것입니다.
 
그렇기 때문에 초깃값을 null이 아닌 [] 빈 배열로 설정해 주고,
API가 정상적으로 호출이 완료되는 시점에 React 렌더링을 완료 시켜주어야 합니다.
아래 그림을 참고해 주세요.
 

🟢 정상 흐름

1. 초기 렌더링

리액트의 초기 렌더링 시에 users 변수에 초깃값을 []로 설정합니다. 동시에 비동기 API 호출을 시작합니다.
 

2. API 정상 호출 완료

API 호출이 정상적으로 완료되면 users의 값이 10개의 배열 값으로 변경됩니다.
 

3. 렌더링 완료

변경된 users의 값으로 렌더링을 완료합니다.

✅ 해결 방법

아래 예시 코드에서 이전 코드는 해당 오류 메시지를 나타냅니다.
여기서 간단하게 오류를 해결하는 방법은
state 변수의 초깃값을 [](빈 배열)로 설정해 주고,
users이 빈 문자열(""), null, undefined가 아닐 때만 렌더링 하는 조건을 추가해 줍니다.
즉,  users &&이라는 조건문을 추가하면 됩니다.
수정 코드를 참고해 주세요.

 

예시 코드

이전 코드

import React, { useEffect, useState } from "react";

function UserPage() {
  const [users, setUsers] = useState(null);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((response) => response.json())
      .then((users) => setUsers(users))
      .catch((error) => console.error("Error fetching users:", error));
  }, []);

  return (
    <div>
      {
        users.map((user) => <li key={user.id}>{user.username}</li>)
      }
    </div>
  );
}

export default UserPage;

 
수정 코드

import React, { useEffect, useState } from "react";

function UserPage() {
  const [users, setUsers] = useState([]); //state 변수 초깃값 변경

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((response) => response.json())
      .then((users) => setUsers(users))
      .catch((error) => console.error("Error fetching users:", error));
  }, []);

  return (
    <div>
      {
        users && // 조건 추가
        users.map((user) => <li key={user.id}>{user.username}</li>)
      }
    </div>
  );
}

export default UserPage;

 

✔️ 에러 발생 시 체크 리스트

  • map 메서드를 사용하고 있는 변수가 null 타입의 변수가 아닌지 확인해 봅니다.
  • 렌더링 되는 시점에 해당 변수의 값이 빈 문자열(""), null, undefined가 아닐 때만 렌더링 하는 조건문이 있는지 확인해 봅니다.
반응형

댓글