최적화
리액트에서의 최적화 기법은 불필요한 연산을 줄여 성능을 향상시키는 것입니다.
리액트 공식 문서에서는 성능 최적화를 위한 방법을 다음과 같이 소개합니다.
최적화 방법
- 코드, 폰트, 이미지 등의 리소스를 압축합니다.
- 메모이제이션을 이용하여 불필요한 연산을 줄입니다.
메모이제이션
메모이제이션이란 연산의 결과를 기억했다가 필요할 때 사용함으로써 불필요한 연산을 방지하는 것입니다.
- useMemo : 함수의 불필요한 재실행을 방지합니다.
- React.memo : 컴포넌트의 불필요한 리렌더링을 방지합니다.
- useCallback : 함수의 불필요한 재생성을 방지합니다.
useMemo
사용하기
문법 : useMemo(() => 연산 결과, [의존성 배열])
- 목적: 값을 기억하고, 성능을 최적화합니다.
- 사용 시점: 계산 비용이 높은 연산을 최적화할 때 사용합니다.
- 사용 방법:
- 값을 계산하는 함수와 의존성 배열을 전달하여 사용합니다.
- 의존성 배열에 있는 값이 변경되지 않으면 이전에 계산된 값을 반환합니다.
- 장점:
- 성능 향상: 이전에 계산된 값을 재사용하여 성능을 향상시킵니다.
- 불필요한 연산 방지: 의존성 배열이 변경되지 않으면 다시 계산하지 않습니다.
할 일 관리 앱 만들기 글의 예제를 기반으로 최적화를 진행해보겠습니다.
아래 예제에서 filteredTodo 함수가 빈번하게 호출되어 불필요한 연산이 발생합니다. 테스트를 위해 filteredTodo 함수에 로깅을 추가하고, 콘솔을 확인해보시면 빈번한 호출이 발생하는 것을 확인할 수 있습니다.
// src/components/TodoList.js
(...)
function TodoList() {
(...)
const filteredTodo = () => {
if (Array.isArray(todo)) {
return todo.filter((item) => item.task.toLowerCase().includes(search.toLowerCase()));
} else {
return [];
}
};
// lookBack 함수가 빈번하게 호출됩니다.
const lookBack = () => {
console.log('lookBack')
const total = todo.length
const done = todo.filter((item) => item.isDone).length
const left = total - done
return { total, done, left }
}
return (
<div>
<h3>할 일 목록 📃</h3>
<input type='text' placeholder="검색어를 입력하세요" onChange={onChangeSearch} value={search} />
<div>
{filteredTodo().map((item) => (
<TodoItem key={item.id} {...item} />
))}
</div>
<div>
{lookBack().total}개 중에 {lookBack().done}개 완료, {lookBack().left}개 남음
</div>
</div>
);
}
export default TodoList;
useMemo를 이용하여 할 일 목록 렌더링 최적화하기
useMemo를 이용하여 filteredTodo 함수의 결과를 기억합니다. useMemo를 사용함으로써 filteredTodo는 함수가 아니라 해당 값을 계산한 결과인 배열을 반환합니다.
// src/component/TodoList.js
import React, { useState, useMemo } from 'react'
import TodoItem from './TodoItem'
export default function TodoList({ todo, onUpdate, onDelete }) {
(...)
// useMemo를 이용하여 filteredTodo 함수의 결과를 기억합니다.
// useMemo를 사용함으로써 filteredTodo는 함수가 아니라 해당 값을 계산한 결과인 배열을 반환합니다.
const filteredTodo = useMemo(() => {
return todo.filter((item) => item.task.toLowerCase().includes(search.toLowerCase()));
}, [search, todo]); // 의존성 배열에 search와 todo를 추가합니다.
// 최적화 테스트
const lookBack = useMemo(() => {
console.log('lookBack')
const total = todo.length
const done = todo.filter((item) => item.isDone).length
const left = total - done
return { total, done, left }
}, [todo]) // 의존성 배열에 todo를 추가합니다.
return (
<div>
(...)
<ul>
// filteredTodo useMemo를 적용한 경우, filteredTodo 자체가 함수가 아니라 해당 값을 계산한 결과인 객체를 반환하기 때문에 ()를 제거합니다.
{filteredTodo.map((item) => (
<TodoItem key={item.id} onUpdate={onUpdate} onDelete={onDelete} {...item} />
))}
</ul>
<div>
// lookBack에 useMemo를 적용한 경우, lookBack 자체가 함수가 아니라 해당 값을 계산한 결과인 객체를 반환하기 때문에 ()를 제거합니다.
{lookBack.total}개 중에 {lookBack.done}개 완료, {lookBack.left}개 남음
</div>
</div>
)
}
- useCallback을 이용하여 함수 재생성 최적화하기
문법 : useCallback(() => 함수, [의존성 배열])
- 목적: 콜백 함수를 기억하고, 성능을 최적화합니다.
- 사용 시점: 콜백 함수가 자주 변경되지 않고, 의존성 배열에 있는 값이 변경될 때 사용됩니다.
- 사용 방법:
- 콜백 함수와 의존성 배열을 전달하여 사용합니다.
- 의존성 배열에 있는 값이 변경되지 않으면 이전에 생성된 콜백 함수를 반환합니다.
- 장점:
- 성능 향상: 이전에 생성된 콜백 함수를 재사용하여 성능을 향상시킵니다.
- 불필요한 함수 생성 방지: 의존성 배열이 변경되지 않으면 새로운 콜백 함수를 생성하지 않습니다.
useCallback을 이용하여 할 일 관리 앱에서 App이 리렌더링될 때마다 addTodo, onUpdate, onDelete 함수가 재생성되는 것을 방지합니다.
// src/component/App.js
import React, { useReducer, useCallback } from 'react'
(...)
function App() {
const [todo, dispatch] = useReducer(reducer, mockTodo)
const addTodo = useCallback((task) => {
const newTodo = {
id: Date.now(),
isDone: false,
task,
createdDate: new Date().getTime(),
}
dispatch({ type: 'ADD', payload: newTodo })
}, [])
const onUpdate = useCallback((id) => {
dispatch({ type: 'UPDATE', payload: id })
}, [])
const onDelete = useCallback((id) => {
dispatch({ type: 'DELETE', payload: id })
}, [])
return (
<div>
<TodoHd />
<TodoEditor addTodo={addTodo} />
<TodoList todo={todo} onUpdate={onUpdate} onDelete={onDelete} />
</div>
)
}
export default App
- React.memo를 이용하여 컴포넌트 최적화하기
문법 : React.memo(컴포넌트)
- 목적: 함수형 컴포넌트의 리렌더링을 방지하여 성능을 최적화합니다.
- 사용 시점: 컴포넌트의 리렌더링이 불필요한 경우에 사용됩니다.
- 사용 방법:
- 함수형 컴포넌트를 React.memo로 래핑하여 사용합니다.
- props가 변경되지 않으면 이전 결과를 재사용하여 리렌더링을 방지합니다.
- 장점:
- 성능 향상: 불필요한 리렌더링을 방지하여 성능을 향상시킵니다.
- 코드 간소화: 명시적인 shouldComponentUpdate 메서드 없이 컴포넌트를 최적화할 수 있습니다.
할 일 관리 앱 적용하기
// src/component/TodoItem.js
(...)
// React.memo를 이용하여 컴포넌트를 최적화합니다.
export default React.memo(TodoItem)
'Front > React' 카테고리의 다른 글
[Hooks] useContext (0) | 2024.03.20 |
---|---|
useReducer - React 배우기 (0) | 2024.03.19 |
React를 이용한 할 일 관리 앱 만들기 (0) | 2024.03.14 |
useEffect, 생명주기 - React 배우기 (0) | 2024.03.11 |
React 카운터 앱 만들기 - component, useState (1) | 2024.03.04 |