React | 컴포넌트 성능 최적화 04 방법2 (react-virtualized 활용)

Kate Jung·2021년 11월 7일
2

React

목록 보기
15/28
post-thumbnail
post-custom-banner

🔶 기존 코드의 문제

🔹 비효율적

기존 컴포넌트(2500개의 컴포넌트)는 스크롤 밖(안 보임. 2491개 컴포넌트)임에도 불구 → 렌더링

🔹 시스템 자원 낭비

배열(todos) 변동 발생 시

→ 배열의 처음~끝까지 컴포넌트로 변환(컴포넌트 내부 map 함수)

→ 안보이는 부분까지 (2491개 컴포넌트)

🔶 react-virtualized 기능

  1. 보이지 않는 (스크롤 되기 전) 컴포넌트 → 렌더링 x & 크기만 차지

  2. 스크롤 되면 → 렌더링

🔶 사용법

🔹 설치

$ yarn add react-virtualized

🔹 방법

◼ 개요 & 사전 작업

  1. 제공하는 List 컴포넌트 사용 → 성능 최적화

  2. 사전 작업

    각 항목의 실제 크기 → px 단위로 파악

    • 크기 파악 시 → 두 번째 항목 확인 하기
      • 이유

        두 번째 항목부터 테두리 포함됨. (1번째 항목 → 테두리 無)

◼ 예시 코드

  1. TodoList.js
import React, { useCallback } from 'react';
import TodoListItem from './TodoListItem';
import './TodoList.scss';
import { List } from 'react-virtualized';

const TodoList = ({ todos, onRemove, onToggle }) => {
  const rowRenderer = useCallback(
    ({ key, index, style }) => {
      const todo = todos[index];
      return (
        <TodoListItem
          todo={todo}
          key={key}
          onRemove={onRemove}
          onToggle={onToggle}
          style={style}
        />
      );
    },
    [todos, onRemove, onToggle],
  );

  return (
    <List
      className="TodoList"
      width={512} // 전체 크기
      height={513} // 전체 높이
      rowCount={todos.length} // 항목 개수
      rowHeight={57} // 항목 높이
      rowRenderer={rowRenderer} // 항목 렌더링 시 쓰는 함수
      list={todos} // 배열
      style={{ outline: 'none' }} // List에 기본 적용되는 outline 스타일 제거
    />
  );
};

export default React.memo(TodoList);
  1. TodoListItem.js
import React from 'react';
import {
  MdCheckBoxOutlineBlank,
  MdCheckBox,
  MdRemoveCircleOutline,
} from 'react-icons/md';
import cn from 'classnames';
import './TodoListItem.scss';

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)}
        >
          {checked ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}
          <div className="text">{text}</div>
        </div>
        <div className="remove" onClick={() => onRemove(id)}>
          <MdRemoveCircleOutline />
        </div>
      </div>
    </div>
  );
};

export default React.memo(
  TodoListItem,
  (prevProps, nextProps) => prevProps.todo === nextProps.todo, // propsAreEqual 함수 사용 -> 특정 값들만 비교
);
  1. TodoListItem.scss
.TodoListItem-virtualized {
  & + & {
    border-top: 1px solid #dee2e6;
  }
  &:nth-child(even) {
    background: #f8f9fa;
  }
}

(...)

◼ rowRenderer 함수

react-virtualized의 List 컴포넌트에서 각 아이템(ex.TodoItem) 렌더링 시 사용

  • List 컴포넌트의 props

  • 파라미터: index, key, style 값 → 객체 타입으로 받아서 사용

◼ List 컴포넌트 사용 시, 필수 props

전달 받은 props 사용 → 자동 최적화

  • 해당 리스트의 전체 크기 (너비, 높이)
  • 각 항목의 높이
  • 각 항목 렌더링 시, 사용해야 하는 함수

◼ rowRenderer 의 리턴 컴포넌트 → props에 맞게 수정

  • 해당 컴포넌트

    TodoListItem.js , TodoListItem.scss

  • [ 수정 사항 ] 최상위에 div로 감싸기

    • className(TodoListItem-virtualized) 설정

      목적: 컴포넌트 사이사이에 테두리 제대로 치기 (→ & + & 활용)

    • props (style) 적용

      목적: 홀짝 항목에 다른 배경 색 적용 (→ &:nth-child(even) 활용)

profile
복습 목적 블로그 입니다.
post-custom-banner

0개의 댓글