useCallback을 사용한 최적화

seongjin·2023년 4월 12일
0

문제상황

export const MarketFeedHome = ({ scrollTopData, followingData }) => {


  const ProductList = async () => {
    
    const followProductList = await followingData.map((list) => {
      return axios(...생략).then((res) => res.data.product);
    });

    return Promise.all(followProductList);
  }

  useEffect(()=>{
    console.log('로딩');
  },[ProductList])
  
  return (
        <>
          {scrollTopData ? <FeedPageHeader /> : <HomepageHeader />}
          <Carousel />
          <main>
                {productData.length > 0 &&
                  productData.map((data) => {
                    return (
                      <ListItem key={Math.random()}>
                        <MarketPostBox data={data} />
                        <MarketPostMoreBtn productId {data.id} />
                      </ListItem>
                    );
                  })}
          </main>
        </>
    
  );
};

ProductList 함수는 props로 전달받는 followingData(팔로잉 유저)를 순회하면서 등록한 상품을 받아오는 api 요청 함수이다. 다만 여기서 문제점은 또 다른 props, 즉 scrollTopData은 스크롤의 높이에 따라 자주 바뀌는 값인데, 프롭스로 내려받는 이 scrollTopData이 바뀔때마다 현재 컴포넌트가 랜더링 된다는 것이다.

밑에 사진을 보면 useEffect의 의존성 배열에 ProductList 함수를 주시하게 해서 객체의 참조값이 변하는지 확인 할 수 있다. 함수가 다시 생성되면 참조값이 변하여 useEffect 안에 로딩이라는 콘솔값이 출력되는 것이다.
즉 스크롤 높이가 변경되어 랜더링이 될때마다 함수도 다시 생성되고 있음을 알 수 있다.

useCallback이란?

React에서 useCallback은 함수형 컴포넌트에서 성능 최적화를 위해 사용되는 Hook 중 하나입니다.
useCallback은 두 개의 매개변수를 받습니다. 첫 번째 매개변수는 콜백 함수이며, 두 번째 매개변수는 의존성 배열입니다. 콜백 함수는 useCallback을 호출할 때 생성됩니다.
만약 의존성 배열이 비어있으면, useCallback은 항상 같은 함수를 반환합니다. 그러나 의존성 배열에 값이 있다면, 배열에 포함된 값 중 하나라도 변경되면, useCallback은 새로운 함수를 생성하고 반환합니다.

문제해결

ProductList를 메모이제이션을 하여 followingData가 변경될때만 다시 함수를 생성하도록 하였다. useCallback을 무분별하게 사용하면 메모이제이션하는 비용이 더 들 수 있으므로 적합한 상황에서 사용하는 것이 좋다.

여기서 사용한 이유는 스크롤의 높이에 따라 바뀌는 scrollTopData라는 프롭스가 자주 바뀌는 값이기 때문에 리랜더링으로 인한 함수의 재생성이 많이 발생한다고 판단하였다. 따라서 이 경우에는 useCallback을 사용하여 메모이제이션 하는 것이 좀 더 적합하다고 판단하였다.

변경 후
const ProductList =useCallback(async () => {
    
    const followProductList = await followingData.map((list) => {
      return axios(...생략).then((res) => res.data.product);
    });

    return Promise.all(followProductList);
  },[followingData]) 

  useEffect(()=>{
    console.log('로딩');
  },[ProductList])

이 경우 scrollTopData의 값이 변경되더라도 콘솔 로딩이 찍히지 않음을 확인함으로써 함수가 재생성이 되지 않음을 유추할 수 있다.

profile
나만의 오답노트

0개의 댓글