프로젝트 진행중 렌더링 최적화 Promise.all

seongjin·2023년 1월 3일
0

트러블슈팅

목록 보기
6/8

문제상황

우리 프로젝트에서는 내가 팔로잉 한 사람들의 상품 목록들만 불러와서 홈페이지에 뿌려주는 것이 구현 목표였다. 하지만 제공된 api에는 그런 기능이 없었다. 때문에 제공된 api 기능중에 내가 팔로잉 한 사람들의 목록을 가져오기해당계정의 상품 리스트 가져오기의 기능을 혼합해서 팀원이 구현하였다.

계정 상품 리스트 가져오기 api 명세 : https:/~~~/product/:accountname
응답 성공시 : [ {...상품1}, {...상품2}, {...상품3} ... ]

// followimgData는 api로 불러온 내가 팔로잉 하고 있는 유저 계정 리스트
// 예 ) [ 철수, 미나, 민우, 유리, 민수 ]

const [productData, setProductData] = useState([]);

useEffect(() => {
     followingData.forEach((list) => {
       axios({
         method: 'get',
         url: `https:~~~/product/${list.accountname}`,
         headers: {
           Authorization: `Bearer ${token}`,
           'Content-type': 'application/json',
         },
       }).then((res) => {
         for (const product of res.data.product) {
           setProductData((v) => {
            return [...v, product]
           });
         }
       });
     });
   }, []);

// MarketPostBox에 props로 data를 전달해 피드에 뿌려주기
productData.map((data) => <MarketPostBox key={data.id} data={data}/> );

문제없이 잘 작동한다. 하지만 내가 팔로잉한 계정들을 순회하면서 가져온 상품 목록들을 가져와 useState값에 넣어줄때마다 재렌더링이 일어나 효율성이 많이 떨어진다는 느낌이 들었다. 예를들어 내가 현재 100명을 팔로잉하고 있다면 100명의 상품들을 useState값에 넣어줄때마다 state값이 변해 100번의 재렌더링이 일어나는 것이다.

해결방안

useState값에 상품들을 모아놨다가 한 번에 전달하는 방법을 고민하였다. 그렇게 된다면 렌더링이 한 번 일어날 것이고 불필요한 재렌더링을 많이 줄여 효율적이라고 생각하였다.
해결방안으로는 Promise.all을 사용하였다. Promise.all은 복수의 URL에 동시에 요청을 보내고, 모두 완료된 후에 한번에 처리할때 사용한다. 즉 여러개의 비동기 처리를 병렬적으로 할 수 있다.

const ProductList = async () => {

  const followProductList = await followingData.map((list) => {

   return axios({
      method: 'get',
      url: `https:~~~/product/${list.accountname}`,
      headers: {
        Authorization: `Bearer ${userToken}`,
        'Content-type': 'application/json',
      },
    }).then(res => res.data.product)

  })
 
  return Promise.all(followProductList)
};

Promise.all을 사용하기 위해 async 함수로 따로 빼주었고 모든 팔로잉 유저의 상품을 불러오고 나서 값을 반환되게 하였다.

async 함수 Return 값

각각의 2차원 배열들을 useState값에 병합하여 넣어주기 위해 flat() 함수 사용.

해당결과

병합한 상품목록들을 useState에 넣어주면 한 번만 렌더링이 일어나게 된다.

useEffect(()=>{
   ProductList().then(res => setProductData( res.flat(1) ))

  },[])
profile
나만의 오답노트

0개의 댓글