[React] 최적화, DOM

정호·2024년 3월 25일
0

TIL

목록 보기
8/15



리액트 DOM의 업데이트

리액트는 가상 돔(Virtual DOM)을 사용하여 실제 돔(Document Object Model)을 업데이트한다.

1. 컴포넌트 렌더링

  • 루트 컴포넌트부터 시작하여 전체 컴포넌트 트리를 생성

2. 가상 돔 업데이트

  • 상태(State) 또는 속성(Props)이 변경되면 리액트는 해당 컴포넌트와 그 자식들의 새로운 가상 돔 트리를 생성

3. 변경 사항 식별

  • 이전 가상 돔 트리와 새로운 가상 돔 트리를 비교하여 식별

4. 실제 돔 업데이트

  • 변경 사항이 식별되면 리액트는 실제 돔에 변경되는 부분만을 대상으로 실제 돔 업데이트를 수행하여 렌더링 성능을 최적화

부모 컴포넌트가 재실행되면 그 자녀 컴포넌트들 또한 리렌더링된다. 상위(App컴포넌트)부모 컴포넌트는 영향을 받지 않는다.

성능 최적화를 위한 memoization 기법

컴포넌트의 재랜더링을 줄이고, 불필요한 연산을 방지하여 애플리케이션의 효율성을 높이는 것은 필수적이다. 이를 위해 리액트는 memo, useCallback, useMemo와 같은 memoization 기법을 제공한다.

memo(컴포넌트 감쌈)

  • 함수형 컴포넌트의 재렌더링을 방지
  • React.memo로 감싸진 컴포넌트는 얕은 비교(shallow comparison)를 통해 props의 변경 여부를 확인하고, 변경이 없으면(=동일하면) 이전 결과를 재사용하여 재랜더링을 방지
  • (재렌더링을 막으려는) 최대한 상위 컴포넌트에 적용하여 불필요한 재랜더링을 방지해야 함

예시

const Counter = memo(function Counter({ initialCount }) {
  // ...
});

initialCountprop에 의해 결정되는 함수형 컴포넌트 래핑
-> 이 값이 변경되지 않으면 컴포넌트가 리렌더링 되지 않음

useMemo(복잡한계산)

  • 컴포넌트 함수 안에 있는 일반 함수들을 감싸고 실행 방지- 계산 비용이 많이 드는 함수나 계산 결과를 재사용하기 위해 사용
  • 의존성 배열의 값이 변경될 때만 다시 계산
    ex) 계산 결과를 캐시하고 재사용해야 할 때 사용

예시

const initialCountIsPrime = useMemo(
  () => isPrime(initialCount),
  [initialCount]
);

initialCount 값이 변경될 때마다 isPrime 함수가 다시 호출되며, 그 결과는 initialCountIsPrime 변수에 저장

useCallback(함수)

  • 콜백 함수를 메모이제이션하여 불필요한 함수 재생성을 방지
  • 함수를 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값으로 쓰면 생기는 문제

key는 리액트에서 상태를 구체적인 컴포넌트 인스턴스에 매핑할때 고려되는 다른 요소이기 때문에
특정 값과 연결된 키 값을 써야함

예시

  const handleIncrement = useCallback(function handleIncrement() {
    // setCounter((prevCounter) => prevCounter + 1);
    setCounterChanges((prevCounterChanges) => [
      { value: 1, id: Math.random() * 1000 },
      ...prevCounterChanges,
    ]);
  }, []);

랜덤으로 id 생성

profile
열심히 기록할 예정🙃

0개의 댓글