React Context

Provider 범위는 값의 소유권과 다시 렌더될 영역으로 정한다

Context는 props 전달을 줄이지만, value 참조가 바뀌면 해당 Context를 읽는 consumer가 다시 렌더된다. 공유할 값, Provider 위치, 참조 안정성을 함께 설계해야 한다.

누가 값을 바꾸는가 상태를 실제로 변경하는 소유자 가까이에 Provider를 둔다.
누가 값을 읽는가 consumer가 있는 가장 가까운 공통 부모까지만 범위를 잡는다.
얼마나 자주 바뀌는가 자주 바뀌는 값은 Context보다 지역 상태가 더 나을 수 있다.

설계 장부

소유권 값을 바꾸는 상태 소유자가 Provider 위치의 후보가 된다.
범위 consumer가 있는 가장 가까운 공통 부모까지만 감싼다.
참조 객체와 함수는 필요할 때 useMemo, useCallback으로 고정한다.
측정 render count와 consumer 수로 영향 범위를 확인한다.

Provider 범위 지도

scope, value, consumer
넓은 Provider

App 전체를 감싸면 작은 변경도 넓게 흔든다

App ThemeProvider 페이지 전체가 같은 value 참조를 본다.
새 value 객체 { theme, setTheme }가 매 렌더 새 참조가 된다.
Header, Sidebar 직접 쓰지 않아도 하위 렌더 범위에 들어갈 수 있다.
Form consumer 자주 바뀌는 draft까지 같이 흔들린다.
넓은 Provider와 새 객체 value가 만나면 영향 범위가 커진다.
가까운 Provider

공유가 필요한 하위 트리만 감싸고 value 참조를 안정화한다

Page local state와 서버 상태는 바깥에 남긴다.
FormProvider form 하위 consumer만 공유 값을 읽는다.
Field 필요한 값만 구독한다.
Submit 안정화된 handler를 읽는다.
가까운 Provider는 Context의 편의와 렌더 범위 제어를 함께 얻는다.

범위 결정 절차

가까운 공통 부모부터
01 consumer 위치 표시 Context를 실제로 읽는 컴포넌트만 트리에서 표시한다.
02 값 소유자 찾기 값을 변경하는 state와 handler가 어느 컴포넌트에 있는지 본다.
03 참조 안정화 객체 value와 callback 참조가 필요할 때만 바뀌도록 고정한다.
04 render count 확인 Provider 이동 전후로 다시 렌더되는 consumer 범위를 비교한다.

Context 분리 기준

split by change rate
값 유형 적절한 위치 Context 후보 여부 점검 기준
자주 변경 입력값, hover, 임시 form 상태는 local state에 둔다. 낮음 매 입력마다 넓은 consumer가 다시 렌더되는지 본다.
공유 설정 theme, locale, auth session처럼 읽는 곳이 넓다. 높음 변경 빈도와 consumer 수가 균형을 이루는지 본다.
함수 참조 dispatch, command handler는 참조 안정성이 중요하다. 조건부 consumer 렌더를 줄이려면 handler 참조를 고정한다.
서버 상태 cache, fetch 결과, mutation 상태는 전용 store나 query cache에 둔다. 낮음 동기화, 재검증, 에러 상태가 Context 밖에서 관리되는지 본다.

위험 신호

blast radius 줄이기
wide blast 작은 value 변경에도 App 대부분이 다시 렌더된다.
new object { user, setUser } 객체가 매번 새 참조면 consumer가 모두 반응한다.
missing provider Provider 누락이 fallback 기본값에 숨어 조용히 동작한다.
mixed concern theme과 form draft처럼 변경 빈도가 다른 값을 한 Context에 둔다.
검증 질문

Provider가 실제 consumer가 있는 가장 가까운 공통 부모에 있는지, value 객체와 callback 참조가 필요할 때만 바뀌는지, Provider 누락과 render count 증가를 테스트나 로그로 볼 수 있는지 확인한다.