본문 바로가기

Computer Programming/[리액트를 다루는 기술]

react-virtualized를 사용한 렌더링 최적화

올해 초 캐나다에서 코딩 공부한지 정말 얼마 안 됬을 때.... 백엔드 친구와 주식 관련 앱을 만들어보려고 했던 적이 있는데 주식 데이터가 실시간으로 너무 많다보니 렌더링이 느리고 성능도 매우 좋지 않았고 최적화를 잘 못하던 시절이라.. 그 시절 내 자신이 정말정말 답답했었다... 😅

 

아무튼 그때 너무 구현해보고 싶었는데 못 했던 부분이

주식 데이터를 보여줄 때 일단 유저에게 짠 하고 처음 보여지는 부분만 먼저 렌더링하고, 유저가 스크롤하거나 zoom하면 그때 필요한 정보를 가져와서 렌더링하는 기능이었다. 비슷한 로직의 라이브러리를 보니 감회가 새롭다 🤩

 

 

이번에는 스크롤 하면서 렌더링 되게 만들어 줄 예정이다

 

 

리스트 아이템의 크기를 먼저 재야하는데, 이 때는 두번째 요소부터 해야 테두리가 합쳐진 크기가 나온다.

 

 

react-virtualized 를 사용하면

import TodoListItem from "./TodoListItem"
import { List } from 'react-virtualized'
import '../styles/TodoList.scss'
import React, { useCallback } from "react"


const TodoList = ({todos, onRemove, onToggle}) => {

    const rowRenderer =  useCallback(
        // 인덱스, 키, 스타일을 파라미터로 받아옴
        ({index, key, style}) => {
            const todo = todos[index];
            return (
                <TodoListItem 
                    todo = {todo}
                    key= {key} //key
                    onRemove={onRemove}
                    onToggle={onToggle}
                    style={style}
                />
            )
        },[todos, onRemove, onToggle])

    return (
        <List 
            className="TodoList" 
            width={485}
            height={513} //전체 높이
            rowCount={todos.length} //항목 개수
            rowRenderer={rowRenderer}
            list = {todos}
            style={{ outline: 'none' }} //리스트 자동 적용 스타일 제거
        />
    )
}

export default React.memo(TodoList);

List를 import 하고 렌더링 할 함수를 정의해준 다음 props로 전달해주면 된다.

여기까지만 하면 size 때문에 에러가 뜨니 TodoListItem 도 가서 바로 수정해줘야 한다.

 

 

import '../styles/TodoListItem.scss'
import cn from 'classnames'
import React from 'react'
import { MdCheckBoxOutlineBlank, MdCheckBox, MdRemoveCircleOutline } from 'react-icons/md'

const TodoListItem = ({todo, onRemove, onToggle, style}) => {
    const { id, text, checked } = todo

    return ( 
        <div className='TodoListItem-virtualized' style={style}>
            <div className="TodoListItem">
                <div className= {cn('checkbox', {checked})} onClick={() => onToggle(id)}>
                {/* //checkbox 클래스인데 checked 일 경우 동적으로 추가 */}
                    {!checked? <MdCheckBoxOutlineBlank /> : <MdCheckBox />}
                    <div className='text'>{text}</div>
                </div>
                <div className='remove' onClick={() => onRemove(id)}>
                    <MdRemoveCircleOutline />
                </div>
            </div>
        </div>
    )
}

export default React.memo(TodoListItem);

새로 받아온 style props를 추가해주고 

 

리스트 아이템들 사이에 border을 넣어주고 짝수번째에는 배경을 다르게 나타나게 하기 위해 리스트 아이템 전체를 감싸는 div 태그를 만들어준다.  (className="TodoListItem")

 

 

 

.TodoListItem-virtualized {
  & + & {
    //엘리먼트 사이
    border-top: 1px solid #dee2e6;
  }
  &:nth-child(even) {
    background: #f8f9fa;
  }
}

border과 배경을 각각 넣어주면 끝!