React에서 Cannot read properties of undefined (reading ‘map’) 에러란?
🔗 관련 에러 해결 가이드
React 개발 중 “Cannot read properties of undefined (reading ‘map’)” 에러를 마주친 경험이 있으신가요? 이 에러는 React 개발자들이 가장 자주 겪는 에러 중 하나입니다. 배열 데이터를 렌더링하려고 할 때 해당 데이터가 undefined 상태여서 map 메서드를 호출할 수 없을 때 발생합니다. 특히 API 호출로 데이터를 받아오는 비동기 상황에서 자주 발생하며, 초보 개발자부터 경험 많은 개발자까지 한 번쯤은 마주치는 흔한 문제입니다. 이 글에서는 이 에러의 원인부터 해결 방법, 그리고 예방법까지 완벽하게 알려드리겠습니다.
🤖 AI 에러 분석 도우미
이 에러는 다음과 같은 상황에서 주로 발생합니다:
- 코드 문법 오류가 있을 때
- 라이브러리나 의존성 문제
- 환경 설정이 잘못된 경우
- 타입 불일치 문제
💡 위 해결법을 순서대로 시도해보세요. 90% 이상 해결됩니다!
에러 상세 분석
이 에러 메시지를 분석해보면 “undefined 객체의 ‘map’ 속성을 읽을 수 없다”는 의미입니다. JavaScript에서 undefined나 null은 속성이나 메서드를 가질 수 없기 때문에 이러한 값에 접근하려고 하면 에러가 발생합니다. React에서는 주로 배열을 map 메서드로 순회하며 컴포넌트를 렌더링하는데, 이때 배열이 아직 정의되지 않았거나 API 응답이 늦어지면 이 에러가 발생합니다.
브라우저 콘솔에서 이 에러를 확인하면 정확히 어느 줄에서 문제가 발생했는지 스택 트레이스를 통해 알 수 있습니다. 보통 TypeError로 분류되며, 런타임 에러이기 때문에 코드 실행 중에 발생합니다. 개발 환경에서는 에러 바운더리가 없다면 화면이 완전히 멈추고 에러 메시지만 표시되는 상황이 발생할 수 있어 사용자 경험에 치명적입니다.
발생 원인 5가지
1. 초기 state가 undefined로 설정된 경우
컴포넌트가 마운트될 때 state의 초기값을 설정하지 않거나 undefined로 설정하면 렌더링 시 map을 호출할 수 없습니다. useState의 초기값을 명시적으로 지정하지 않으면 이 문제가 발생합니다.
2. API 데이터 로딩 중인 경우
가장 흔한 원인으로, 비동기 API 호출이 완료되기 전에 컴포넌트가 렌더링되면 데이터가 아직 undefined 상태입니다. useEffect로 데이터를 가져올 때 첫 렌더링에서는 데이터가 없는 상태이기 때문에 에러가 발생합니다.
3. props 전달 오류
부모 컴포넌트에서 자식 컴포넌트로 배열을 전달할 때 props 이름이 잘못되었거나 전달되지 않은 경우, 자식 컴포넌트에서는 undefined를 받게 됩니다.
4. 잘못된 객체 경로 접근
중첩된 객체 구조에서 데이터를 가져올 때 경로가 잘못되면 undefined를 반환합니다. 예를 들어 response.data.items가 아니라 response.items로 접근하면 문제가 발생할 수 있습니다.
5. 조건부 렌더링 미흡
데이터의 존재 여부를 확인하지 않고 바로 map을 사용하면 데이터가 없을 때 에러가 발생합니다. 로딩 상태나 에러 상태에 대한 처리 없이 렌더링하는 경우 특히 문제가 됩니다.
해결방법 7가지 (코드 포함)
해결법 1: 초기값을 빈 배열로 설정
가장 기본적이고 효과적인 방법입니다. useState의 초기값을 빈 배열로 설정하면 첫 렌더링에서도 map이 정상적으로 작동합니다.
import { useState, useEffect } from 'react';
function UserList() {
// 초기값을 빈 배열로 설정
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('https://api.example.com/users')
.then(res => res.json())
.then(data => setUsers(data));
}, []);
return (
{users.map(user => (
{user.name}
))}
);
}
해결법 2: Optional Chaining과 기본값 사용
옵셔널 체이닝(?.)과 Nullish 병합 연산자(??)를 사용하여 안전하게 데이터에 접근합니다.
function ProductList({ data }) {
const products = data?.products ?? [];
return (
{products.map(product => (
{product.name}
))}
);
}
해결법 3: 조건부 렌더링으로 로딩 처리
데이터가 로드되기 전까지 로딩 메시지를 표시하여 에러를 방지합니다.
function PostList() {
const [posts, setPosts] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.example.com/posts')
.then(res => res.json())
.then(data => {
setPosts(data);
setLoading(false);
});
}, []);
if (loading) return 로딩 중...;
if (!posts) return 데이터가 없습니다.;
return (
{posts.map(post => (
{post.title}
))}
);
}
해결법 4: Array.isArray()로 배열 여부 확인
데이터가 실제로 배열인지 확인한 후 map을 사용합니다.
function CommentList({ comments }) {
return (
{Array.isArray(comments) && comments.map(comment => (
{comment.text}
))}
);
}
해결법 5: 단축 평가(Short-circuit) 사용
논리 AND 연산자를 사용하여 간단하게 조건부 렌더링을 구현합니다.
function ItemList({ items }) {
return (
{items && items.map(item => (
{item.name}
))}
);
}
해결법 6: try-catch와 Error Boundary 사용
예상치 못한 에러를 처리하기 위해 에러 바운더리를 구현합니다.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return 데이터를 불러오는 중 문제가 발생했습니다.
;
}
return this.props.children;
}
}
function App() {
return (
);
}
해결법 7: 커스텀 Hook으로 데이터 페칭 관리
재사용 가능한 커스텀 Hook을 만들어 안전하게 데이터를 관리합니다.
function useFetch(url) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(err => {
setError(err);
setLoading(false);
});
}, [url]);
return { data, loading, error };
}
function DataList() {
const { data, loading, error } = useFetch('https://api.example.com/data');
if (loading) return 로딩 중...;
if (error) return 에러 발생: {error.message};
return (
{data.map(item => (
{item.name}
))}
);
}
예방법과 베스트 프랙티스
항상 초기값을 명확하게 설정하세요. useState를 사용할 때는 데이터 타입에 맞는 초기값(배열의 경우 [], 객체의 경우 {})을 설정하는 습관을 들이세요. TypeScript를 사용한다면 타입을 명시하여 컴파일 시점에 에러를 잡을 수 있습니다.
방어적 프로그래밍을 실천하세요. 외부 데이터를 사용할 때는 항상 존재 여부를 확인하고, Optional Chaining과 기본값을 활용하여 안전하게 접근하세요. API 응답 구조가 변경될 수 있다는 점을 항상 염두에 두어야 합니다.
로딩 상태와 에러 상태를 관리하세요. 비동기 데이터를 다룰 때는 반드시 로딩, 성공, 실패 세 가지 상태를 모두 처리해야 합니다. React Query나 SWR 같은 라이브러리를 사용하면 이러한 상태 관리를 더 쉽게 할 수 있습니다.
PropTypes나 TypeScript로 타입 검증을 하세요. props로 전달되는 데이터의 타입을 명확히 정의하면 개발 단계에서 많은 에러를 미리 방지할 수 있습니다. 특히 팀 프로젝트에서는 필수적입니다.
마무리
“Cannot read properties of undefined (reading ‘map’)” 에러는 React 개발에서 피할 수 없는 문제지만, 원인을 이해하고 적절한 해결책을 적용하면 쉽게 해결할 수 있습니다. 이 글에서 소개한 7가지 해결 방법 중 상황에 맞는 방법을 선택하여 적용해보세요. 가장 중요한 것은 초기값 설정과 조건부 렌더링을 습관화하는 것입니다. 이러한 베스트 프랙티스를 따르면 더 안정적이고 유지보수하기 쉬운 React 애플리케이션을 개발할 수 있습니다. 앞으로는 이 에러를 마주치더라도 당황하지 말고 체계적으로 해결해나가시기 바랍니다.
📚 함께 읽으면 좋은 글
Cannot read properties of undefined (reading ‘map’) 에러 해결법 – 원인 분석부터 완벽 해결까지
📅 2025. 9. 9.
🎯 Cannot read properties of undefined (reading ‘map’)
Cannot update a component while rendering 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 4.
🎯 Cannot update a component while rendering
Error: Element type is invalid 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 2.
🎯 Error: Element type is invalid
Maximum update depth exceeded 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 2.
🎯 Maximum update depth exceeded
Maximum update depth exceeded 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 1.
🎯 Maximum update depth exceeded
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
이 글에서 가장 도움이 된 부분은 어떤 것인가요?
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 React 에러부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!