← 전체 글로 돌아가기

웹 개발

개발 초보가 프론트엔드 버그를 찾을 때 빠지기 쉬운 함정

복잡한 문제로 보이지만 실제로는 간단한 원인인 경우가 많다. 먼저 확인해야 할 것들.

프로젝트가 복잡해질수록 문제도 복잡해 보인다. 그런데 실제로는 간단한 원인인 경우가 많다. 특히 초보자들이 빠지기 쉬운 함정이 있다.

브라우저 캐시를 의심한다

가장 먼저 할 일은 캐시를 지우는 것이다.

# 개발 서버 종료 후 캐시 정리
rm -rf .next
rm -rf dist
rm -rf node_modules/.cache

그리고 브라우저 캐시도 지운다:

  • Chrome: Cmd/Ctrl + Shift + Delete
  • 혹은 DevTools에서 Network 탭의 "Disable cache" 체크

변경사항이 안 보이면 대개 캐시 문제다.

콘솔의 에러 메시지를 정확히 읽는다

Browser DevTools를 켠다. Console 탭을 본다. 에러가 있으면 무조건 확인한다.

Uncaught TypeError: Cannot read property 'map' of undefined

이 에러가 있으면 어딘가 배열이 undefined인 상태로 .map()을 호출했다는 뜻이다.

실제로 페이지에 도달했는지 확인한다

URL을 다시 확인한다. 404 페이지는 아닌가?

curl -I https://example.com/blog/post

응답 코드가 200인지, 404인지, 3xx 리다이렉트인지 확인한다.

API 호출이 실제로 일어나는지 본다

DevTools의 Network 탭에서 요청을 본다.

  • 요청이 보내졌나?
  • 응답 상태가 200인가, 500인가?
  • 응답 본문이 비어있지는 않나?

API 문제라면 여기서 드러난다.

변수 값을 직접 출력한다

간단하지만 효과적인 방법이다:

const data = await fetchData()
console.log('data:', data)  // 직접 출력
console.log('type:', typeof data)  // 타입 확인

React DevTools를 켜서 컴포넌트의 props와 state를 본다.

조건부 렌더링 로직을 확인한다

if (loading) return <Loading />
if (!data) return <Error />
return <Content data={data} />

이 순서가 맞나? 데이터가 없을 때 먼저 체크하는 게 맞다.

또는 옵셔널 체이닝을 쓰는 게 나을 수도 있다:

return <div>{data?.name}</div>

의존성 배열을 확인한다 (React)

useEffect(() => {
  fetchData()
}, [])  // 빈 배열은 마운트할 때 1번만 실행

Effect가 한 번도 실행되지 않거나 무한 실행되면, 여기서 확인해야 한다.

useEffect(() => {
  fetchData()
}, [userId])  // userId가 바뀔 때마다 실행

타입을 확인한다

TypeScript를 쓴다면 타입 에러가 있나?

npm run type-check

혹은 IDE에서 빨간 밑줄이 없나?

최근 코드 변경사항을 돌아본다

git diff
git log -5 --oneline

최근에 뭘 바꿨는지 본다. 그 변경사항이 이 문제와 연관되지 않았나?

단순하게 만들어본다

문제를 재현하는 최소한의 예제를 만든다.

function SimpleTest() {
  return <div>Hello World</div>
}

이것부터 시작해서 조금씩 복잡해진다. 어디서 문제가 생기는지 추적한다.

로컬과 배포 환경의 차이를 본다

로컬에서는 괜찮은데 배포 후에 문제가 생긴다면, 환경 변수나 API 엔드포인트를 확인한다.

# 로컬
echo $API_URL

# 배포 환경
ssh user@server "echo $API_URL"

다르면 거기가 원인이다.

결론

초보자들은 복잡한 원인을 찾으려고 한다. 하지만 대개는 캐시, 에러 메시지 놓침, 변수 값 확인 부족 같은 간단한 실수다. DevTools를 켜고, 콘솔 에러를 읽고, 변수 값을 출력해보면 대부분의 문제를 찾을 수 있다.