다음과 같이 지뢰찾기 페이지가 있습니다.
컴포넌트 구조는 다음과 같은데요.
Tr
은 row의 개수, 즉 10
개가 되구요
Td
는 각 셀의 개수, 100
개가 됩니다.
사실상 Props로 지뢰찾기의 필요한 데이터를 전달하는 것은 비효율적으로 보이는데요
그래서 Context API를 사용해봅시다.
MineSearch
쪽을 Provider
로 사용하면 다음과 같습니다.
<TableContext.Provider value={value}>
<Form />
<div>{timer}</div>
<Table />
<div>{result}</div>
</TableContext.Provider>
MineSearch
컴포넌트에서 timer
state를 관리하여 1초마다 변경이 되는데요
그러면 Form
컴포넌트는 어떻게 될까요?
계속 렌더링이 됩니다.
Form
컴포넌트를 최적화 해봅시다.
const Form = memo(() => { ... }
React.memo
를 사용하는 겁니다. React.memo
는 이전 props
와 현재 props
를 비교하여 랜더링 여부를 결정하는데요.
지금은 props
를 전달받는 것이 없으니 재랜더링이 되지 않겠네요
부모 컴포넌트와 독립적
으로 작동하고, 컴포넌트 내부 state
에만 의존하여 리렌더링이 발생합니다.
<TableContext.Provider value={value}>
여기서 value
값이 변하면 어떻게 될까요?
하위 모든 컴포넌트는 재렌더링이 됩니다.
MineSearch
컴포넌트에서 timer
로 인해 1초마다 재랜더링이 발생하는데요
이 때 value 자체는 변하지 않지만 새로운 value를 만들기 때문에 참조값이 바뀌어 버리는데요
그래서 100개나 있는 Td
컴포넌트들이 1초마다 재랜더링이 됩니다.
value
자체를 메모리제이션하는 훅을 사용해야 하는데요
const value = useMemo(() => ({ tableData, halted, dispatch }), [tableData, halted]);
객체를 메모리제이션 할때에는 useMemo
를 사용하면 됩니다.
의존성 배열
값들이 변경되었을 때만 다시 계산하는데요.
그 결과 Td
컴포넌트는 timer
로 인해 재렌더링 되는 현상을 막을 수 있습니다.
만약 cell을 눌렀을 때 모든 Td
컴포넌트가 재렌더링 될 필요가 있을까요?
필요한 부분만 랜더링 해주면 됩니다.
Td
쪽도 Cell data
를 메모리 제이션 해주면 되는데요
const RealTd = memo(({ onClickTd, onRightClickTd, data}) => { ...}
onClickTd
, onRightClickTd
는 함수이기 때문에 useCallback
으로 메모리제이션 해주었구요
data
은 값이기 때문에 따로 해주지 않습니다.
Td
까지 최적화를 해주면 필요한 Td
컴포넌트만 랜더링 됩니다.