리액트는 가상 돔(Virtual DOM)을 사용하여 실제 돔(Document Object Model)을 업데이트한다.
1. 컴포넌트 렌더링
컴포넌트 트리
를 생성2. 가상 돔 업데이트
상태(State)
또는 속성(Props)
이 변경되면 리액트는 해당 컴포넌트와 그 자식들의 새로운 가상 돔 트리
를 생성 3. 변경 사항 식별
비교
하여 식별 4. 실제 돔 업데이트
변경되는 부분
만을 대상으로 실제 돔 업데이트를 수행하여 렌더링 성능을 최적화부모 컴포넌트가 재실행되면 그 자녀 컴포넌트들 또한 리렌더링된다. 상위(App컴포넌트)부모 컴포넌트는 영향을 받지 않는다.
컴포넌트의 재랜더링을 줄이고, 불필요한 연산을 방지하여 애플리케이션의 효율성을 높이는 것은 필수적이다. 이를 위해 리액트는
memo
,useCallback
,useMemo
와 같은 memoization 기법을 제공한다.
- 함수형 컴포넌트의 재렌더링을 방지
React.memo
로 감싸진 컴포넌트는얕은 비교
(shallow comparison)를 통해props
의 변경 여부를 확인하고, 변경이 없으면(=동일하면) 이전 결과를 재사용하여 재랜더링을 방지- (재렌더링을 막으려는) 최대한 상위 컴포넌트에 적용하여 불필요한 재랜더링을 방지해야 함
예시
const Counter = memo(function Counter({ initialCount }) {
// ...
});
initialCount
prop에 의해 결정되는 함수형 컴포넌트 래핑
-> 이 값이 변경되지 않으면 컴포넌트가 리렌더링 되지 않음
- 컴포넌트 함수 안에 있는 일반 함수들을 감싸고 실행 방지- 계산 비용이 많이 드는 함수나 계산 결과를 재사용하기 위해 사용
의존성 배열
의 값이 변경될 때만 다시 계산
ex) 계산 결과를 캐시하고 재사용해야 할 때 사용
예시
const initialCountIsPrime = useMemo(
() => isPrime(initialCount),
[initialCount]
);
initialCount
값이 변경될 때마다 isPrime
함수가 다시 호출되며, 그 결과는 initialCountIsPrime
변수에 저장
콜백 함수
를 메모이제이션하여 불필요한 함수 재생성을 방지- 함수를
useEffect
의 의존성으로 사용할 때 매번 새로운 함수가 생성되는 것을 방지하여 불필요한 재랜더링을 줄임
--> 의존성 배열이 변경되지 않는 한 항상 동일한 콜백 함수를 반환
ex)자식 컴포넌트에게 전달되는 콜백 함수가 자식 컴포넌트 내부에서 사용되는 경우
예시
const handleDecrement = useCallback(function handleDecrement() {
// setCounter((prevCounter) => prevCounter - 1);
setCounterChanges((prevCounterChanges) => [
{ value: -1, id: Math.random() * 1000 },
...prevCounterChanges,
]);
}, []);
const handleIncrement = useCallback(function handleIncrement() {
// setCounter((prevCounter) => prevCounter + 1);
setCounterChanges((prevCounterChanges) => [
{ value: 1, id: Math.random() * 1000 },
...prevCounterChanges,
]);
}, []);
함수를 부모 컴포넌트에 전달할 때 메모이제이션된 콜백 함수
를 사용함으로써 불필요한 렌더링을 방지
컴포넌트가 처음 렌더링될 때 한 번만 생성
❖ 빈 의존성 배열 전달
콜백 함수
는 컴포넌트가 처음 렌더링될 때 한 번만
생성
특정한 변수를 전달
해당 변수가 변경될 때마다 새로운 콜백 함수가 생성
key는 리액트에서 상태를 구체적인 컴포넌트 인스턴스에 매핑할때 고려되는 다른 요소이기 때문에
특정 값과 연결된 키 값을 써야함
예시
const handleIncrement = useCallback(function handleIncrement() {
// setCounter((prevCounter) => prevCounter + 1);
setCounterChanges((prevCounterChanges) => [
{ value: 1, id: Math.random() * 1000 },
...prevCounterChanges,
]);
}, []);
랜덤으로 id 생성