간단하지만 조금 더 유연한 메모이징

pengooseDev·2023년 4월 15일
0

문제점 인식

문득, 한 가지 고민점이 생겼다.
보통 메모이징은 export하기 전, memo로 컴포넌트를 감싸 export하는 방식으로 진행했다.

그런데, 해당 컴포넌트가 공통 컴포넌트여서 다른 컴포넌트 여기저기에서 쓰인다면?
메모이징이 불필요한 상황이 대부분이고 딱 한 부분에서만 메모이징을 해야한다면?
그럼 결국 불필요한 메모이징을 남발하는 꼴이지 않나..?


간단한 해결책

결국 함수 컴포넌트의 관점에서 생각해보면 Vitual DOM의 컨셉을 가진 객체일 뿐이다.
메모이징이 필요한 컴포넌트에서 선택적으로 메모이징을 해주면 해결 될 문제였다.

(위의 코드는 어디까지나 예시일 뿐, props로 전달되는 taskData는 참조타입 데이터이기 때문에 이에 대한 메모이징도 진행해야한다.)

의사결정 분기

  1. 해당 컴포넌트가 여러 곳에서 사용되는 공통 컴포넌트인가?
  2. 힙 메모리를 사용할만큼 메모이징의 가치가 있는 컴포넌트인가?

위의 상황에서 컴포넌트 자체에 메모이징을 진행할 것인지, import해온 컴포넌트에서 진행할 것인지 상황에 맞게 선택을 하면 된다.


적용

/* TaskCard 컴포넌트 메모이제이션 */
const MemoizedTaskCard = memo(TaskCard);

export function Project() {
  const { id: param } = useParams();
  const { errorHandler } = useErrorHandler();
  const isMobileM = useMediaQuery(DEVICES.MOBILEM);
  const isMobileL = useMediaQuery(DEVICES.MOBILEL);
  const isTablet = useMediaQuery(DEVICES.TABLET);
  const isLaptop = useMediaQuery(DEVICES.LAPTOP);

  const gridColumnCount = useMemo(() => {
    if (isLaptop) return 4;
    if (isTablet) return 3;
    if (isMobileL) return 2;
    if (isMobileM) return 1;
    return 1;
  }, [isLaptop, isTablet, isMobileL, isMobileM]);

  const { data: projectData, isLoading } = useQuery<ProjectDataForm>(
    [QUERY.KEY.PROJECT_DATA, param],
    () => getProjectData(param as string),
    {
      ...QUERY.DEFAULT_CONFIG,
      onError: (error: unknown) => errorHandler(error),
    }
  );

  /* useMemo를 통한 props(projectData) 객체 메모이제이션*/
  const memoizedTasks = useMemo(() => {
    return projectData?.tasks.map((taskData: TaskDataForm) => (
      <MemoizedTaskCard taskData={taskData} key={taskData.id} />
    ));
  }, [projectData?.tasks]);

  if (isLoading) return <Loading />;

  return (
    <Wrapper>
      {projectData && <ProjectInformation projectData={projectData} />}
      <ProjectBoard gridColumnCount={gridColumnCount}>
        {memoizedTasks}
        <NewTaskButton />
      </ProjectBoard>
    </Wrapper>
  );
}

0개의 댓글