기존 컴포넌트(2500개의 컴포넌트)는 스크롤 밖(안 보임. 2491개 컴포넌트)임에도 불구 → 렌더링
배열(todos) 변동 발생 시
→ 배열의 처음~끝까지 컴포넌트로 변환(컴포넌트 내부 map 함수)
→ 안보이는 부분까지 (2491개 컴포넌트)
보이지 않는 (스크롤 되기 전) 컴포넌트 → 렌더링 x & 크기만 차지
스크롤 되면 → 렌더링
$ yarn add react-virtualized
제공하는 List 컴포넌트 사용 → 성능 최적화
사전 작업
각 항목의 실제 크기 → px 단위로 파악
이유
두 번째 항목부터 테두리 포함됨. (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);
- 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 함수 사용 -> 특정 값들만 비교
);
- TodoListItem.scss
.TodoListItem-virtualized {
& + & {
border-top: 1px solid #dee2e6;
}
&:nth-child(even) {
background: #f8f9fa;
}
}
(...)
react-virtualized의 List 컴포넌트에서 각 아이템(ex.TodoItem) 렌더링 시 사용
List 컴포넌트의 props
파라미터: index, key, style 값 → 객체 타입으로 받아서 사용
전달 받은 props 사용 → 자동 최적화
해당 컴포넌트
TodoListItem.js
, TodoListItem.scss
[ 수정 사항 ] 최상위에 div
로 감싸기
className(TodoListItem-virtualized
) 설정
목적: 컴포넌트 사이사이에 테두리 제대로 치기 (→ & + &
활용)
props (style
) 적용
목적: 홀짝 항목에 다른 배경 색 적용 (→ &:nth-child(even)
활용)