인프런 커뮤니티 질문&답변

강두희님의 프로필 이미지
강두희

작성한 질문수

[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지

11.3) Context 분리하기

Context 분리 질문

작성

·

115

0

Context를 이용하여 props를 분리하고, onUpdate, onCreate같이 한번만 수행되는 함수들은 useMemo를 이용하여 메모이제이션을 한다고 했습니다. 아래 코드처럼요

  const memoDispatch = useMemo(() => {
    return {
      onCreate,
      onUpdate,
      onDelete,
    };
  }, []);

그런데 이전 시간에 각각의 함수를 useCallback를 통해 메모이제이션 했는데 한번 더 하는 이유가 이해 가지 않아 질문 드립니다. 아래 코드처럼 useCallback를 통해 처음 렌더링 될 때만 실행되고 이후에는 실행되지 않도록 코드를 작성 했는데 맨 위의 코드처럼 한번 더 감싼? 이유가 잘 이해가 되지 않습니다.

const onCreate = useCallback((content) => {
    dispatch({
      type: "CREATE",
      data: {
        id: idRef.current++,
        isDone: false,
        content: content,
        date: new Date().getTime(),
      },
    });
  }, []);

  const onUpdate = useCallback((targetId) => {
    dispatch({
      type: "UPDATE",
      targetId: targetId,
    });
  }, []);

  const onDelete = useCallback((targetId) => {
    dispatch({
      type: "DELETE",
      targetId: targetId,
    });
  }, []);

답변 2

0

이정환 Winterlood님의 프로필 이미지
이정환 Winterlood
지식공유자

안녕하세요 이정환입니다.

이것은 최적화를 위한 것입니다. 더 구체적으로 말씀드리자면 DispatchContext.Provider 컴포넌트가 리렌더링 되지 않도록 설정하기 위함입니다.

 

우리 코드에서는 App 컴포넌트에서 DispatchContext.Provider 컴포넌트에게 Props로 객체 형태로 묶인 3개의 함수를 내려보내주고 있습니다. (onCreate, onUpdate, onDelete) 기억나시죠?

이때 위 3개의 함수들을 useMemo를 활용하지 않고 그냥 일반적인 객체로 묶어서 다음과 같이 value Props로 전달해주게 되면

<DispatchContext.Provider value={{onCreate, onUpdate, onDelete}}/> 

App 컴포넌트가 리렌더링 될 때 마다 이 객체 또한 다시 생성됩니다. 그럼 DispatchContext.Provider 컴포넌트는 전달받는 Props가 달라졌기 때문에 리렌더링이 발생하게 됩니다.

물론 객체 내부에 포함되는 3개의 함수는 useCallback으로 묶여 다시 생성되지 않는것이 맞습니다. 그러나 함수가 재생성 되는게 아니라 함수를 묶는 객체 자체가 다시 생성되기 때문입니다. 그리고 그렇게 재생성된 객체는 새로운 주소값을 가질것이기 때문에 결국 DispatchContext.Provider 컴포넌트에서는 Props가 변경되었다고 판단하고 리렌더링이 진행됩니다.

따라서 다음과 같이 useMemo를 활용해 객체 자체를 재생성하지 않도록 처리해주는 일이 필요합니다.

  const memoDispatch = useMemo(() => {
    return {
      onCreate,
      onUpdate,
      onDelete,
    };
  }, []);

그럼 어차피 context로 관리하고 useMemo를 활용해 재생성하지 않도록 처리 하였으니 useCallback은 사용하지 않아도 되는거겠죠?

이정환 Winterlood님의 프로필 이미지
이정환 Winterlood
지식공유자

네 딱 이 경우에만 한정해서 말씀드리자면 useCallback은 활용하지 않으셔도 괜찮습니다.

0

안녕하세요, 인프런 AI 인턴입니다.

강두희님의 질문에 대한 답변으로, Context를 분리하는 이유와 메모이제이션 기법(특히 useMemouseCallback의 활용)에 대한 설명이 필요해 보입니다. useMemo를 사용하여 Context의 Value에 포함된 함수들(onCreate, onUpdate, onDelete)을 각각 useCallback으로 메모이제이션한 이후 한 번 더 useMemo로 묶는 이유는, 전체 객체를 하나의 단위로 메모이제이션하여 최적화를 도모하기 위함입니다.

각 함수가 useCallback에 의해 메모이제이션이 되어 있더라도, 이 함수들을 포함하는 객체 자체가 컴포넌트가 리렌더링 될 때마다 새로 생성될 경우, 이 객체를 사용하는 컴포넌트들 역시 불필요하게 리렌더링 될 수 있습니다. 따라서, 이러한 함수들을 포함하는 객체 자체도 useMemo를 통해 메모이제이션함으로써, 해당 객체의 참조가 변하지 않게 함으로써 리렌더링을 효율적으로 관리할 수 있습니다.

이와 유사한 상황에 대한 이전 질문에 대한 답변에서 관련 내용을 찾아볼 수 있습니다.

  • Context 분리 및 최적화 관련 답변에서 이정환 강사님이 useMemouseCallback을 활용하여 함수와 상태를 관리하는 방법과 그 필요성에 대해 상세히 설명하고 있습니다. 이 질문에서는 Context를 분리하는 방법 및 여러 최적화 기법에 대한 깊이 있는 이해를 도울 수 있습니다.

강두희님의 코드에서 useCallback으로 함수들을 각각 메모이제이션한 것은 좋은 접근입니다. 추가로 useMemo를 사용하여 이 함수들을 하나의 객체로 묶는 이유는, 이 객체가 하나의 단위로서 변하지 않음을 보장하고, 이를 통해 해당 객체를 의존성으로 사용하는 다른 훅이나 컴포넌트를 효과적으로 최적화하기 위함입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

강두희님의 프로필 이미지
강두희

작성한 질문수

질문하기