• [일기장 만들기_12] 최적화 3 - useCallback 🙄

    2022. 2. 24.

    by. 용디

    목표

    - 현재 진행한 코드 중 낭비되고 있는 부분 찾아 최적화 하기


    찾는 방법

    어떤 컴포넌트가 낭비되고 있는지 크롬 도구로 찾을 수 있다. 이미지와 같이 일기 삭제를 했는데 에디터 전체가 렌더 된것으로 확인된다.


    👀 코드를 수정해보자

    1. onCreate함수에 React.memo로 묶기

    // 아래처럼 직접 묶는건 함수길이가 길어질 경우 햇갈릴 수 있음.
    const DiaryEditor = React.memo(({onCreate}) => { ~~
    
    // 그럴경우 하단 export default에 묶어주는 방식으로 하기!
    export default React.memo(DiaryEditor);

    React.memo로 묶인 DiaryEditor를 내보내는 것 이기 때문에 기존방식과 결과가 동일하다.

     

    2. useEffect로 언제 렌더가 일어나는지 찍어보자

    useEffect(() => {
      console.log('DiaryEditor Render');
    });

     

    ✋ 잠깐만! 새로고침만 했는데 콘솔에 로그가 2번 찍혔다? ✋

    이유는 부모인 App 컴포넌트가 마운트 될 때 data의 state의 초기값인 빈 배열값으로 렌더가 한번 되고, 뒤이어 마운트 될 시점에 호출했던 getData함수가 setData에 전달을 하면서 data state가 한번더 바뀌게 된다. 즉, App 컴포넌트는 마운트 되자마자 2번의 렌더링이 되고 자식요소 또한 2번의 렌더를 거친다.

     

    💡 onCreate 함수가 재 생성 되지 않아야만 DiaryEditor 컴포넌트를 React.memo와 함께 최적화 할 수 있다!

     

     

    😁 그렇다면.. onCreate를 React.memo로 묶어주면 되겠지?? 😁

     

    두둥..

    놉..!

    React.memo는 함수가 반환하는 값을 다시 사용 할 수 있도록 디펜던시 어레이를 기준으로 메모이제이션을 도와주는 기능이기 때문에 onCreate함수에 사용하게 되면 원본그대로를 DiaryEditor에 보내는것이 아닌 값으로만 전달되기 때문에 오류가 난다.

     

    이때, useCallback을 이용하면 해결 할 수 있다!


    ✋ 여기서 useCallback 이란?

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

    메모이제이션된 콜백함수를 반환한다. 즉, 값이 아닌 콜백함수를 다시 반환해 준다.

    두번째 인자로 전달한 값이 변화하지 않으면, 첫번째 인자인 콜백함수를 계속 재사용 할 수 있도록 도와주는 기능을 한다.


    👀 마저 수정해보자..

    3. 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;
        setData([newItem, ...data]);
      }, []);

    🤔 useCallback을 둘러주고 게시물 추가를 해보니 총 게시물은 1개로 확인됐다.

     

    현재의 state값을 참조해야하는데 콜백함수안에 갇혀있고, 댑스를 빈배열로 전달받았기 때문에 참조를 못하는 상태.

    그래서 댑스에 data state를 넣어줘야하는데 재생성 되지않아야 하기 때문에 빈배열을 유지 시켜줘야 한다. (대혼란)

     

    그렇기 때문에.. 이런 경우에는 함수형 업데이트를 사용하여 함수전달 해줘야 한다.

     

    4. 함수형 업데이트

      const onCreate = useCallback((author, content, emotion) => {
        ~~~~~
        setData((data) => [newItem, ...data]);
      }, []);

    최신의 state를 인자를 통해 참고할 수 있도록 해주어 댑스를 비울수 있도록 도와준다.

     

    5. 최적화 확인

    새로고침시에 콘솔에 DiaryEditor Render가 1번 찍히는것을 확인 할 수 있다.


    ​Demo : winterlood​ - codesandbox

     

     

    댓글