티스토리 뷰

node.js/React.js

[React] Infinite Scroll 구현

IT공부블로그 2022. 5. 2. 23:38
728x90
반응형

참조 : https://medium.com/benx-tech-blog/react%EC%9D%98-%EB%A0%8C%EB%8D%94%EB%A7%81-%ED%8D%BC%ED%8F%AC%EB%A8%BC%EC%8A%A4-%EA%B0%9C%EC%84%A0%EA%B8%B0-%EB%B6%80%EC%A0%9C-1000%EA%B0%9C-%EC%9D%B4%EC%83%81%EC%9D%98-%EC%95%84%EC%9D%B4%ED%85%9C%EC%9D%84-%EA%B0%80%EC%A7%84-%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0-8403a6c47b1c

 

React의 렌더링 퍼포먼스 개선기 (부제: 1000개 이상의 아이템을 가진 리스트를 개선하기)

안녕하세요, 미누캉입니다. 근 2년 오랜만에 글을 쓰게되었는데요, 그 사이에 위버스 컴퍼니 웹개발팀으로 이직을 하게 되었습니다 😇

medium.com

https://markoskon.com/displaying-hundreds-of-images-with-react-window-and-gatsby-image/

 

Displaying hundreds of images with react-window and gatsby-image | Dev Diary

See how to display hundreds of images with react-window and gatsby-image by building an app that displays all the Hearthstone cards in a grid. You can also see the compromises you have to make.

markoskon.com

 

스크롤형태의 많은 데이터를 보여주기 위해 사용

 

위 라이브러리 사용하지않고 만들때는 데이터가 많아 질수록 굉장히 느려지는 현상이 발생하여

 

현재 보여지는 부분만 DOM에 그려지는 위 라이브러리 사용

 

 <EasyVirtualizedScroller
    hasMore={true}
    onLoadMore={loadMore}
    useParentScrollElement={true}
    overscanRowCount={5}
    loader={<SkeletonGallery/>}
>
   {
       galleryList.map( (element, index) => {

        if(element.title !== ''){

            return (
                <ButtonBase 
                    sx={ 
                        { width: 500, height: 190, textAlign: 'left', flexWrap: 'nowrap'
                    }} 
                    key={element.id}
                    onClick={() => handleClickGallery(element.url, element.galleryId)}
                >
                    <Gallery
                        {...element}
                    />
                </ButtonBase>
            )
        }else{
            return (
                <SkeletonGallery key={index}/>
            )
        }
    })
   }
</EasyVirtualizedScroller>

react-virtualized 라이브러리 사용 시 스크롤 마다 전체 데이터 리스트가 다 render 되는게 발생해서

 

react-easy-virtualized 라이브러리를 사용하였지만

 

알고보니 memoize-one 라이브러리를 사용하여 추가 최적화를 진행해주면 스크롤 마다 render 되는일은 발생하지않음

 

리스트는 react-easy-virtualized를 사용하여 구현

 

그리드는 reac-window를 사용하여 구현

 

 <Paper
    sx={{
        p: 2,
        maxWidth: 1120,
        height: 690,
        flexGrow: 1,
        backgroundColor: (theme) =>
        theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
    }}
>
     <AutoSizer>
        {({ width, height }) => {
            const columnCount = Math.floor(width / gridOption.imgWidth);
            const itemData = createItemData(galleryInfo.data.files, columnCount);
            const rowCount = Math.ceil(galleryInfo.data.files.length / columnCount);

            return (
                <FixedSizeGrid
                    className="grid"
                    width={width}
                    height={height}
                    columnCount={columnCount}
                    columnWidth={gridOption.imgWidth}
                    rowCount={rowCount}
                    rowHeight={gridOption.imgHeight}
                    itemData={itemData}
                    style={{marginLeft: '33px'}}
                >
                    {Cell}
                </FixedSizeGrid>
            )
        }}
    </AutoSizer>
</Paper>

동적배열 형태가 아니기때문에 스크롤 시  모든 데이터가 render 되게 하지않게 하기위해서는

 

memoize-one 라이브러리로 최적화가 필요하다

 

const createItemData = memoizeOne((imageData, columnCount) => ({
    imageData,
    columnCount
}));

const Cell = memo(({ columnIndex, rowIndex, style, data }: any) => {
    
    const { imageData, columnCount } = data
    const singleColumnIndex = columnIndex + rowIndex * columnCount
    const image = imageData[singleColumnIndex]

    if(singleColumnIndex >= imageData.length) return ( <></>);

    return (
      <div style={{ ...style,  }}>
        {
            image && image.img !== ''
            ?
            <GalleryImg
                id={image.id} 
                img={image.img}
            />
            :
            <Skeleton/>
        }
      </div>
    )
  }, areEqual)

각 행의 그리는 Cell 함수에 넘겨주는 데이터를 생성하는 createItemData 함수를

최초 1번만 호출하고 그 후에는 memoize 한 결과값을 리턴하기 때문에 스크롤 마다 모든 데이터가 render 되지않음

 

 

내 스크롤에는 각 행마다 이미지가 들어있기 때문에

 

스크롤 시 마다 새로 그려지는 행의 이미지를 매번 가져오는 문제가 있어

 

useSWR을 이용하여 이미지들을 전역 상태로 저장하여 관리한다

728x90
반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함