부족한 부분 보충학습 2

Rock Kyun·2023년 12월 19일
1
post-custom-banner

React 최적화

React에 최적화를 하는 이유

  • 불필요한 리렌더링을 방지하기 위해
    (초기 로딩 속도를 빠르게 할 수 있는 최적화도 있다 _ lazy import 같은 것)

간단한 개념 요약

React.memo - 컴포넌트를 캐싱

useCallback - 함수를 캐싱

useMemo = 값을 캐싱


자세한 개념

1. React.memo

  • 아래와 같은 상황에서 Parent Component가 업데이트 되면
    Child Component가 같이 업데이트 되는 불필요한 렌더가 일어난다.
    (Parent Component가 업데이트마다 Child Component의 console.log 메세지가 출력된다.)
// 부모 컴포넌트
function Parent() {
  const [count, setCount] = useState(0);

  const addCount = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h1>부모 컴포넌트입니다.</h1>
      <Child />
    </div>
  );
}

export default Parent

// 자식 컴포넌트
function Child() {
  console.log("업데이트 되었습니다");

  return (
    <div>
      <h1>자식 컴포넌트 입니다.</h1>
    </div>
  );
}

export default Child

React.memo를 적용

  • 위와 같은 상황의 경우 Child Component를 메모리에 캐싱하여
    Parent Component에게 받은 props가 변경되는 것이 아니라면
    렌더가 일어나지 않도록 한다.
    (Parent Component의 count가 변경되어도 Child Component의 console.log가 출력되지 않음)
// 부모 컴포넌트
function Parent() {
  const [count, setCount] = useState(0);

  const addCount = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h1>부모 컴포넌트입니다.</h1>
      <h3>{count}</h3>
      <Child />
    </div>
  );
}

export default Parent

// 자식 컴포넌트
function Child() {
  console.log("업데이트 되었습니다");

  return (
    <div>
      <h1>자식 컴포넌트 입니다.</h1>
    </div>
  );
}

// 컴포넌트를 React.memo로 감싸주면 끝
export default React.memo(Child)

2. useCallback

  • 인자로 들어오는 함수memoization 하는 것
  • Parent Component에서 props로 함수를 Child Component로 내려주었을 때
    React.memo를 적용한 Child Component에 불필요한 렌더가 다시 일어난다.
  • props로 내려준 initCount 함수가 재생성 되기 때문에
    Child Component에서는 새로운 props를 전달 받았다고 인지하기 때문

JS에서 함수는 일급'객체'로 취급되는데
객체는 메모리 공간 속 별도의 공간에 주소값으로 저장된다.
따라서 재렌더가 일어나면 새로운 주소값에 이전 함수와 똑같이 생긴 함수가 저장되고
React는 기존의 함수와 똑같은 함수라도 새로운 함수로 인지하고 재렌더가 발생한다.

예시

// 부모 컴포넌트
function Parent() {
  const [count, setCount] = useState(0);

  const addCount = () => {
    setCount(count + 1);
  };

  const initCount = () => {
    setCount(0);
  }

  return (
    <div>
      <h1>부모 컴포넌트입니다.</h1>
      <h3>{count}</h3>
      <Child setCount={setCount}/>
    </div>
  );
}

export default Parent

// 자식 컴포넌트
function Child({setCount}) {
  console.log("업데이트 되었습니다");

  return (
    <div>
      <h1>자식 컴포넌트 입니다.</h1>
      <button onClick={setCount}>초기화</button>
    </div>
  );
}

export default React.memo(Child)

useCallback을 적용

  • 특정 조건이 아니라면 해당 함수의 재렌더를 막는 것
  • 의존성 배열로 조건을 설정할 수 있다.
// 부모 컴포넌트
function Parent() {
  const [count, setCount] = useState(0);

  const addCount = () => {
    setCount(count + 1);
  };

  // 함수를 useCallback으로 감싸준다
  const initCount = useCallback(() => {
    setCount(0);
  }, [])

  return (
    <div>
      <h1>부모 컴포넌트입니다.</h1>
      <h3>{count}</h3>
      <Child setCount={setCount}/>
    </div>
  );
}

export default Parent

// 자식 컴포넌트
function Child({setCount}) {
  console.log("업데이트 되었습니다");

  return (
    <div>
      <h1>자식 컴포넌트 입니다.</h1>
      <button onClick={setCount}>초기화</button>
    </div>
  );
}

export default React.memo(Child)

3. useMemo

  • 값을 memoization 하는 것 (예. 함수의 반환 값, 객체)

예시 1. 무거운 작업을 하는 함수의 반환 값을 저장

  • 컴포넌트가 재렌더 될 때마다 실행되는 함수가 있는데
    그 함수가 엄청나게 무거운 작업을 거쳐 값을 반환하는 함수이다.
    이런 함수를 품고 있는 컴포넌트가 있다면 재렌더 시 delay가 생긴다.
function HeavyWork() {
  // 무거운 함수
  const heavyFunc = () => {
    for (let i = 0; i < 10000000000; i++) {
      return 100;
    }
  };
  // 무거운 함수를 재렌더마다 실행
  const value = useMemo(() => heavyFunc(), []);
  console.log(`value는 ${value}입니다`);

  return (
    <div>
      <h1>{value}</h1>
    </div>
  );
}

export default React.memo(Child);

예시 2. 객체의 불변성을 유지하기 위한 useMemo

function Test() {
  const [isAlive, setIsAlive] = useState(false);

  // 불변성을 유지해야 하는 객체
  // 특정 값이 변경될 때가 아니라면 현재의 주소값을 유지한다.
  const person = useMemo(() => {
    return {
      name: "Lee",
      age: "21",
      isAlive: isAlive ? "생존" : "사망",
    };
  }, [isAlive]);

  return (
    <div>
      <h1>{value}</h1>
    </div>
  );
}

export default React.memo(Child);

useMemo 주의사항

  • 너무 많이 사용하면 메모리 공간을 너무 많이 사용하게 되서
    오히려 성능이 떨어질 수 있다.
post-custom-banner

0개의 댓글