Context는 ‘변경될 때마다 Provider 아래 전부를 리렌더’하지 않는다. 바뀐 값을 실제로 읽는(consume) 컴포넌트만 리렌더된다.
value가 Object.is 기준으로 달라지면(원시값 변경, 혹은 객체 참조 변경), 해당 Context를 읽는 자식들이 리렌더된다. Context를 안 읽는 컴포넌트는 이 변화로 인해 리렌더 대상이 아니다.memo/shouldComponentUpdate 등으로 스킵해도 소비자까지 값이 내려가면 소비자는 업데이트된다. 이것도 문서에 명시돼 있다.데모와 동일하게 “Render all” 같은 버튼으로 최상단에서 강제로 렌더를 유도하면 트리 전체가 한 번씩 비교를 거치기 때문에 넓게 리렌더가 보인다. 반면 “Change state(컨텍스트 값 변경)”는 Context 소비자만 반응한다 — 바로 위 규칙 때문.
useMemo로 {foo, setFoo} 묶음 메모)로 필요없는 변경을 줄인다. (단, React Compiler를 쓰면 이런 메모 작업 상당 부분이 자동화된다. 아래 5) 참조)props.children겉보기에 비슷해 보여도 자식을 “어디서 생성했는지”가 다르면 결과가 갈린다.
<Child />를 생성부모가 리렌더될 때마다 새 React Element 객체가 생긴다. 이전 렌더의 자식 요소와 참조가 달라 React가 하위 비교를 위해 내려가게 된다. (이 과정에서 자식이 실제로 화면 갱신을 하느냐는 별개지만, 적어도 “들여다보는 비용”이 발생)
props.children으로 받아 그대로 내보내기부모가 같은 children 참조를 계속 전달하면, React는 동일 요소(참조 동일)로 보고 서브트리 진입을 스킵(bailout)할 수 있다. 그래서 데모에서 ChildrenStyleTwo는 카운트가 바뀌어도 전달된 children 참조가 그대로면 하위로 안 내려간다. 이건 Context와 무관하게 리컨실리에이션의 ‘요소 참조 동일성’ 규칙 때문이다.
요약: Context가 아니라, 요소(React Element) 참조의 안정성이 리렌더 범위를 좌우한다. 같은 이유로 부모가 매 렌더마다 새 요소를 만들어서 children에 넣어주면, 다시 내려가게 된다.
value={{ foo, setFoo }}처럼 객체를 매번 새로 만들면 소비자 전부 리렌더. useMemo로 묶음 참조를 고정한다.children 참조 안정화: 부모에서 만든 자식 요소를 같은 참조로 재사용하거나, 자식 컴포넌트는 memo로 감싸 props 변동 없을 때 호출 억제. (불필요한 메모 남발은 금물)“use memo” 지시어로 부분 도입도 가능. Next/Expo 등에서 가이드가 제공된다. 이 환경에서는 위에서 말한 children 참조 안정화와 같은 미세 튜닝의 체감 효과가 줄어들 수 있다.문서/실무에서 자주 지적되듯, 컨트롤드 인풋은 타이핑마다 상태 갱신 → 리렌더다. 이것 자체는 정상 동작. 다만 성능 민감 구간이라면:
useDeferredValue로 비싼 하위 렌더 지연useRef + 비제어 입력 조합 (제출 시점에만 읽기)props.children)을 혼동하는 데서 온다.Object.is 비교 규칙. react.dev+1useContext: 소비자 리렌더 전파 규칙. react.devmemo: 부모 리렌더에서도 props 불변이면 스킵 가능. react.dev"use memo" 지시어. react.dev+2react.dev+2