Next.js
React에서 상태 업데이트 제대로 디버깅하기
React의 상태 업데이트가 기대대로 안 되면 화면만 봐서는 알 수 없습니다. 로그와 상태 변화를 함께 봐야 합니다.
React에서 "클릭했는데 화면이 안 바뀐다" 하면 당황스럽다. 화면만 보면 상태가 제대로 업데이트됐는지, 렌더링됐는지 알 수 없다.
상태 변화 로깅하기
React Developer Tools 확장이 있지만, 제일 직관적인 방법은 콘솔 로그다.
const [count, setCount] = useState(0);
const handleClick = () => {
console.log('클릭 전 count:', count);
setCount(count + 1);
console.log('setCount 호출 후 count:', count); // 아직 바뀌지 않음!
};
React의 상태 업데이트는 비동기다. setCount를 호출한 직후에 로그를 찍어도 이전 값을 본다. 다음 렌더링에서 새 값을 본다.
이벤트 흐름 추적하기
복잡한 상황에선 이벤트가 어디서 버려지는지 추적해야 한다.
const handleClick = () => {
console.log('[Step 1] 클릭 감지');
const result = validateInput();
if (!result.valid) {
console.log('[Step 2] 검증 실패:', result.error);
return;
}
console.log('[Step 2] 검증 통과');
setLoading(true);
console.log('[Step 3] 로딩 상태로 변경');
fetch('/api/data')
.then(res => res.json())
.then(data => {
console.log('[Step 4] 서버 응답:', data);
setData(data);
console.log('[Step 5] 데이터 상태 업데이트');
})
.catch(err => {
console.error('[Step 4] 서버 에러:', err);
})
.finally(() => {
setLoading(false);
console.log('[Step 5] 로딩 종료');
});
};
어느 Step에서 막혔는지 명확히 보인다.
렌더링 추적하기
상태는 업데이트되는데 화면이 안 바뀐다면, 컴포넌트가 리렌더링되지 않았을 수 있다.
function MyComponent({ data }) {
useEffect(() => {
console.log('MyComponent 렌더링됨, data:', data);
});
return <div>{data}</div>;
}
콘솔에 로그가 안 보이면 이 컴포넌트가 리렌더링되지 않은 것이다. 부모 컴포넌트에서 상태 업데이트가 전파되지 않거나, React.memo나 useMemo 때문일 수 있다.
모바일에서 확인하기
PC에선 되는데 모바일에서 안 될 수 있다. 특히 터치와 마우스 이벤트 구분, 뷰포트 크기, 키보드 입력이 다르다.
- PC:
onClick→ 마우스 클릭 - 모바일:
onClick→ 터치 두 번, 길게 누르기 등으로도 발동
const handleTouch = (e) => {
console.log('터치 이벤트:', e.type, e.touches.length);
};
return <button onTouchStart={handleTouch}>테스트</button>;
React DevTools로 상태 스냅샷 찍기
개발자 도구 → Components → 컴포넌트 선택 → Hooks에서 현재 상태를 볼 수 있다. 클릭 전후로 상태가 바뀌었는지 비교한다.
최종 확인: 네트워크와 상태를 함께 보기
Network 탭과 Console을 함께 열어둔다. 클릭하면:
- Console에서 로그가 순서대로 나오는지
- Network에서 요청이 가는지
- 응답이 오는지
- 응답 후 상태가 바뀌는지
모든 단계를 함께 보면 어디가 끊겼는지 명확해진다.
마지막으로, 상태 업데이트 문제는 대부분 각 단계를 제대로 추적하지 않아서다. 로그 몇 줄로 대부분 해결된다.