Files
sam-react-prod/claudedocs/architecture/[IMPL-2025-11-18] ssr-hydration-fix.md
byeongcheolryu 65a8510c0b fix: 품목기준관리 실시간 동기화 수정
- BOM 항목 추가/수정/삭제 시 섹션탭 즉시 반영
- 섹션 복제 시 UI 즉시 업데이트 (null vs undefined 이슈 해결)
- 항목 수정 기능 추가 (useTemplateManagement)
- 실시간 동기화 문서 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 22:19:50 +09:00

3.6 KiB

SSR Hydration 에러 해결 작업 기록

문제 상황

1차 에러: useData is not defined

  • 위치: ItemMasterDataManagement.tsx:389
  • 원인: 리팩토링 후 useData()useItemMaster() 변경 누락
  • 해결: 함수 호출 변경

2차 에러: Hydration Mismatch

Hydration failed because the server rendered HTML didn't match the client
  • 원인: Context 파일에서 localStorage를 useState 초기화 시점에 접근
  • 영향: 서버는 초기값 렌더링, 클라이언트는 localStorage 데이터 렌더링 → HTML 불일치

근본 원인 분석

문제가 되는 패턴 (React SPA)

const [data, setData] = useState(() => {
  if (typeof window === 'undefined') return initialData;
  const saved = localStorage.getItem('key');
  return saved ? JSON.parse(saved) : initialData;
});

문제점:

  • 서버: typeof window === 'undefined' → initialData 반환
  • 클라이언트: localStorage 값 반환
  • 결과: 서버/클라이언트 HTML 불일치 → Hydration 에러

SSR-Safe 패턴 (Next.js)

const [data, setData] = useState(initialData);

useEffect(() => {
  try {
    const saved = localStorage.getItem('key');
    if (saved) setData(JSON.parse(saved));
  } catch (error) {
    console.error('Failed to load data:', error);
    localStorage.removeItem('key');
  }
}, []);

장점:

  • 서버/클라이언트 모두 동일한 초기값으로 렌더링
  • useEffect는 클라이언트에서만 실행
  • Hydration 후 localStorage 데이터로 업데이트
  • 에러 처리로 손상된 데이터 복구

수정 내역

AuthContext.tsx

  • 2개 state: users, currentUser
  • localStorage 로드를 단일 useEffect로 통합
  • 에러 처리 추가

ItemMasterContext.tsx

  • 13개 state 전체 SSR-safe 패턴 적용
  • 통합 useEffect로 모든 localStorage 로드 처리
  • 버전 관리 유지:
    • specificationMasters: v1.0
    • materialItemNames: v1.1
  • 포괄적 에러 처리 및 손상 데이터 정리

예상 부작용 및 완화

Flash of Initial Content (FOIC)

  • 현상: 초기값 표시 → localStorage 데이터로 전환
  • 영향: 매우 짧은 시간 (보통 눈에 띄지 않음)
  • 완화: 필요시 loading state 추가 가능

localStorage 데이터 손상

  • 대응: try-catch로 감싸고 손상 시 localStorage 클리어
  • 결과: 기본값으로 재시작하여 앱 정상 동작 유지

테스트 결과

  • Hydration 에러 해결
  • localStorage 정상 로드
  • 서버/클라이언트 렌더링 일치
  • 에러 없이 페이지 로드

향후 고려사항

  • 나머지 8개 Context (Facilities, Accounting, HR, etc.)는 실제 사용 시 동일 패턴 적용 필요
  • 복잡한 초기 데이터가 있는 경우 서버에서 데이터 pre-fetch 고려
  • Critical한 초기 데이터는 서버 컴포넌트에서 직접 전달하는 방식 검토 가능

참고 문서


관련 파일

프론트엔드

  • src/contexts/AuthContext.tsx - SSR-safe 패턴 적용된 인증 Context
  • src/contexts/ItemMasterContext.tsx - SSR-safe 패턴 적용된 품목 마스터 Context (13개 state)
  • src/components/items/ItemMasterDataManagement.tsx - 품목기준관리 컴포넌트

참조 문서

  • claudedocs/auth/[IMPL-2025-11-07] authentication-implementation-guide.md - 인증 구현 가이드
  • claudedocs/architecture/[REF-2025-11-19] multi-tenancy-implementation.md - 멀티테넌시 구현 (localStorage 패턴)