안녕하세요! 오늘도 어김없이 콘솔창을 붉게 물들인 그 녀석... 다들 한 번쯤은 만나보셨죠? "Cannot read properties of undefined". 진짜 프론트엔드 개발을 하면서 이 에러를 한 번도 안 만나본 사람은 없을 거라고 자신 있게 장담합니다.
처음 코딩을 시작하고 이 빨간 줄을 봤을 때는 '내가 뭘 그렇게 큰 잘못을 했나' 싶어서 심장이 철렁 내려앉았는데요. 하도 맞다 보니까 이제는 '아, 또 데이터 늦게 왔구나?' 하고 헛웃음부터 나오더라고요. (웃음) 오늘은 실무에서 이 지긋지긋한 에러가 도대체 왜 발생하는지, 그리고 두 번 다시 우리를 괴롭히지 못하게 방어하는 코드를 어떻게 찰지게 짜야 하는지 제 수많은 삽질 경험을 담아 정리해 보겠습니다.

1. 도대체 "undefined의 속성을 읽을 수 없다"는 게 무슨 뜻일까?
이 에러 메시지를 직역하자면 "undefined의 속성을 읽을 수 없다"는 뜻입니다. 자바스크립트는 참 유연하면서도 가끔은 너무 무심한 친구예요. 없는 상자 안에서 물건을 꺼내려고 하면 "어? 너 지금 빈 상자 뒤지고 있는데? 거기 아무것도 없어~" 하고 부드럽게 넘어가 주면 참 좋을 텐데 말이죠.
현실은 가차 없이 런타임 에러를 던지며 사용자가 보고 있던 멀쩡한 화면을 새하얗게(이른바 White Screen of Death) 날려버립니다. 주로 객체(Object)나 배열(Array) 데이터 안에 있는 깊은 속성 값을 꺼내 쓰려고 할 때, 그 최상위 객체 자체가 아직 존재하지 않아서(undefined 상태라서) 발생하는 대참사입니다.
2. 가장 흔한 원인: 성격 급한 브라우저와 비동기 통신(API)의 엇박자
실무에서 이 녀석을 만나는 가장 뻔하고 흔한 상황은 바로 '비동기 통신(API 호출)' 때입니다. 프론트엔드는 서버에 "유저 정보 좀 주세요!" 하고 API 요청을 보내고, 서버에서 데이터를 받아와서 화면에 예쁘게 뿌려줘야 하죠.

그런데 자바스크립트 이 녀석은 성격이 너무 급해서 서버 응답이 도착할 때까지 기다려주질 않아요. 일단 데이터가 없는 상태의 빈 화면부터 냅다 그려버립니다. 서버 데이터가 아직 태평양 건너오지도 않았는데, 우리는 컴포넌트에 userData.profile.imageUrl 같은 코드를 적어놓았으니 당연히 사달이 납니다. userData 변수가 아직 데이터를 못 받아서 undefined인 상태인데, 그 안에서 profile을 억지로 찾으려고 하니 브라우저가 화를 내는 거죠.
3. 실전 해결책 1: 내 수명을 늘려준 구원투수, 옵셔널 체이닝(?.)
이럴 때 제가 가장 사랑하고 즐겨 쓰는 구원 투수가 바로 옵셔널 체이닝(Optional Chaining, ?.)입니다. ES2020에 도입된 이후로 프론트엔드 개발자들의 수명이 3년은 연장되었다는 우스갯소리가 있을 정도죠.
// 에러를 유발하는 시한폭탄 같은 코드 (X)
const userProfileImage = userData.profile.imageUrl;
// 마음이 편안해지는 방어 코드 (O)
const userProfileImage = userData?.profile?.imageUrl;
보이시나요? 접근하려는 객체 뒤에 물음표(?)와 마침표(.)를 딱 붙여주면 끝입니다! "userData가 존재하면 profile을 찾고, profile이 존재하면 imageUrl을 찾아라. 만약 중간에 하나라도 없으면 냅다 에러를 던지지 말고, 조용히 undefined를 반환해라!" 라는 아주 우아하고 젠틀한 뜻이 되죠.
4. 또 다른 원인: React에서 Props나 State 초기값을 깜빡했을 때
두 번째로 자주 겪는 억울한 상황은 React에서 컴포넌트에 Props를 넘겨주거나 State 초기값을 잘못 설정했을 때예요. 상위 컴포넌트에서 하위 컴포넌트로 데이터를 내려주는데, 실수로 오타를 내거나 데이터를 깜빡하고 안 넘겨주면 어떻게 될까요? 하위 컴포넌트 입장에서는 "어? 나한테 준다던 데이터 어디 갔어?" 하면서 또 어김없이 undefined 에러를 뿜어냅니다.
5. 실전 해결책 2: 기본값 세팅과 조건부 렌더링(&&)으로 철벽 방어하기
이럴 때는 논리 연산자(&&)를 사용해서 조건부 렌더링을 걸어주거나, 구조 분해 할당(Destructuring)을 할 때 기본값(Default Value)을 꼼꼼하게 세팅해 주는 습관을 들이는 것이 좋습니다.
// 부모로부터 user 데이터를 받는 컴포넌트
const UserCard = ({ user }) => {
// user가 undefined로 넘어와도 에러가 나지 않도록 빈 객체({})와 기본값 방어 로직 추가!
const { name = '이름 없음', age = 0, hobbies = [] } = user || {};
return (
<div>
{/* 데이터가 있을 때만 안전하게 렌더링 (조건부 렌더링) */}
{user && <h1>{name}님의 프로필</h1>}
<p>나이: {age}</p>
<p>취미 개수: {hobbies.length}</p>
</div>
);
};
이렇게 방어막을 2중, 3중으로 쳐두면 아무리 서버가 늦게 응답하거나 실수로 빈 데이터가 들어와도 화면 전체가 먹통이 되는 끔찍한 일은 막을 수 있습니다.
마무리하며
사실 이 "Cannot read properties of undefined" 에러는 여러분의 코딩 실력이 부족해서라기보다는, 데이터가 언제 화면에 도착하는지 그 복잡한 '타이밍'을 잠시 놓쳤을 때 발생하는 경우가 대부분입니다.
처음에는 붉은색 글씨가 무섭고 당황스럽지만, 오늘 알아본 옵셔널 체이닝(?.)이나 조건부 렌더링(&&), 그리고 구조 분해 할당 시 기본값을 설정하는 든든한 방어 코드를 손가락에 익숙해지도록 무한 반복해 보세요. 어느새 툭하면 터지던 빨간 콘솔창 대신, 어떤 데이터 지연이나 누락에도 끄떡없는 견고하고 평화로운 하얀색 콘솔창을 만나보실 수 있을 거예요. 오늘 제 피 땀 눈물이 섞인 삽질 기록이 누군가의 칼퇴와 멘탈 보존에 조금이나마 도움이 되었길 진심으로 바랍니다!
[다음 포스팅 예고] 데이터가 안 와서 발생하는 에러를 훌륭하게 방어해 냈으니, 다음번에는 브라우저를 꽁꽁 얼려버리는 무시무시한 녀석을 만나볼 차례입니다. 바로 멀쩡하던 노트북 쿨러를 비행기 이륙 소리로 만들어버리는 "무한 렌더링(Infinite Loop)에 빠진 React 컴포넌트 구출하기" 편으로 돌아오겠습니다. useEffect의 의존성 배열(Dependency Array) 지옥에서 붉은 에러를 뿜으며 허우적대본 경험이 있으시다면, 다음 글도 절대 놓치지 마세요! 그럼 다들 오늘도 버그 없는 평온한 하루 보내시길 응원합니다!
[실무에서 복붙해 쓰는 에러 해결 및 트러블슈팅 가이드 #02] 내 노트북 이륙 막기! React 무한 렌더
안녕하세요! 지난번 "Cannot read properties of undefined" 에러 해결편은 많은 분들의 칼퇴에 도움이 되셨나요? 오늘은 프론트엔드 개발자라면 누구나 한 번쯤 겪어봤을 법한 아주 오싹한 경험을 이야기
code-bricks.tistory.com