미라클 메모리

목차

불 필요한 리 렌더링을 막자 !

현재 App 컴포넌트는 자연스럽게 2번 리렌더링 된다. 첫 번째 렌더링은 코드 실행을 위한 렌더링 그 다음 렌더링은 언제 일어날까?

const getData = async () => {
    const res = await fetch(
      "<https://jsonplaceholder.typicode.com/comments>"
    ).then((res) => res.json());

    const initData = res.slice(0, 20).map((it) => {
      return {
        author: it.email,
        content: it.body,
        emotion: Math.floor(Math.random() * 5) + 1,
        created_date: new Date().getTime(),
        id: dataId.current++,
      };
    });

    setDate(initData);
  };

getData 함수를 실행하면서 데이터를 불러온다. 불러온 데이터로 인하여 서버에 비동기 요청을 보내고 비동기 요청의 결과물이 data 상태값에 저장이 된다. 상태값이 저장이 되는 순간 리렌더링이 한번 더 일어난다.

const onCreate = useCallback((author, content, emotion) => {
    const created_date = new Date().getTime();
    const newItem = {
      author,
      content,
      emotion,
      created_date,
      id: dataId.current,
    };
    dataId.current += 1;
    setDate([newItem, ...data]);
  }, []);

이때 props를 통해서 전달이 되는 onCreate 함수 역시 2번 출력이 된다. 그리고 이후에 다른 함수들 onRemove, onEdit 함수에 의해서 data값이 변경이 될 때마다 onCreate 함수 역시도 props로 새로운 값을 DiaryEditor 함수에 내려보낸다. 그에 따라서 Create 부분의 컴포넌트가 다시 렌더링 되는것이다. 이것은 상당히 비효율적이다.

useCallback을 사용하여 최적화하기

UseCallback

Hooks API Reference - React

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

메모이제이션된 콜백을 반환합니다.

인라인 콜백과 그것의 의존성 값의 배열을 전달하세요. useCallback은 콜백의 메모이제이션된 버전을 반환할 것입니다. 그 메모이제이션된 버전은 콜백의 의존성이 변경되었을 때에만 변경됩니다. 이것은, 불필요한 렌더링을 방지하기 위해 (예로 shouldComponentUpdate를 사용하여) 참조의 동일성에 의존적인 최적화된 자식 컴포넌트에 콜백을 전달할 때 유용합니다.

memoizedCallback 함수에 useCallback을 사용하면 렌더링 타이밍을 정할 수 있다.

const onCreate = useCallback(
    (author, content, emotion) => {
      const created_date = new Date().getTime();
      const newItem = {
        author,
        content,
        emotion,
        created_date,
        id: dataId.current,
      };
      dataId.current += 1;
      setDate([newItem, ...data]);
    },
    [data]
  );

data값이 변경되는 시점을 의존성 배열에 넘긴 후 onCreate함수를 실행하도록 해보자. 하지만 이 방법은 옳지 않다 왜냐하면 내가 의도한 바는 data의 값이 변화가 될때마다 onCreate 함수가 렌더링 되는것이 아닌 그저 그외의 data값이 변하더라도 onCreate함수가 호출되지 않은 것이기 때문이다. 이렇게 data를 의존성 배열로 보낼 경우에 여전히 CRUD가 일어날 때마다 onCreate함수는 실행이 된다 그러면 어떻게 해야할까?

함수형 업데이트를 하자.

const onCreate = useCallback((author, content, emotion) => {
    const created_date = new Date().getTime();
    const newItem = {
      author,
      content,
      emotion,
      created_date,
      id: dataId.current,
    };
    dataId.current += 1;
    setDate((data) => [newItem, ...data]);
  }, []);