-
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: 20240728_about_redux_이재용 (#65)
- Loading branch information
Showing
1 changed file
with
169 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
--- | ||
layout: post | ||
title: "함수 컴포넌트에서의 Redux 성능 최적화" | ||
author: "이재용" | ||
categories: "프론트엔드 기술블로그" | ||
banner: | ||
image: "https://velog.velcdn.com/images/jjh099/post/3fa558f9-2050-402b-aee7-350c02fc6ef2/image.jpeg" | ||
background: "#000" | ||
height: "100vh" | ||
min_height: "38vh" | ||
heading_style: "font-size: 4.25em; font-weight: bold; text-decoration: underline" | ||
tags: ["redux", "리덕스", "최적화"] | ||
--- | ||
## 들어가며 | ||
|
||
Redux는 리액트 애플리케이션의 강력한 상태 관리 방법을 제공하지만, 잘못 사용하면 성능 이슈가 발생할 수 있습니다. 이번 글에서는 Redux를 사용할 때 적용할 수 있는 성능 최적화 기법에 대해 알아보겠습니다. | ||
|
||
--- | ||
|
||
## **Redux와 함수 컴포넌트에서 발생하는 성능 이슈** | ||
|
||
다음과 같이 크게 2가지 문제를 생각해 볼 수 있습니다. | ||
|
||
- **불필요한 리렌더링** : Redux 상태가 변경될 때마다, 연결된 컴포넌트들은 리렌더링됩니다. 하지만 모든 상태 변경이 해당 컴포넌트와 관련된 것은 아닐 수 있습니다. 이로 인해 불필요한 리렌더링이 발생하여 성능 저하를 일으킬 수 있습니다. | ||
- **비효율적인 상태 선택과 계산** : 컴포넌트에서 필요한 상태를 선택할 때 불필요한 연산이나 깊은 비교가 발생하면 렌더링 성능에 영향을 미칩니다. | ||
|
||
이제, 본격적으로 Redux 성능을 최적화 할 수 있는 방법에 대해 알아봅시다. | ||
|
||
--- | ||
|
||
## **Redux 성능 최적화** | ||
|
||
### **1. React Redux Hooks의 효율적 사용** | ||
|
||
첫 번째 최적화 기법은 `useSelector` 훅을 최적화하는 방법입니다. | ||
|
||
- **`useSelector` 훅의 최적화**: | ||
- `useSelector`는 Redux 스토어의 상태를 선택하여 컴포넌트에서 사용할 수 있게 해주는 훅입니다. 기본적으로 `useSelector`는 참조 비교를 수행하기 때문에, 선택한 상태가 새로운 객체나 배열로 반환되면 내용이 같더라도 리렌더링이 발생할 수 있습니다. | ||
- **해결 방법**: | ||
- `shallowEqual`을 사용하여 얕은 비교를 통해 불필요한 리렌더링을 방지할 수 있습니다. 이는 특히 상태가 객체나 배열일 때 유용합니다. | ||
- 상태가 복잡한 중첩된 객체인 경우, 커스텀 비교 함수를 사용하여 객체 내 특정 값만 비교하도록 최적화할 수 있습니다. | ||
|
||
두 번째로, `createSelector`를 사용한 메모이제이션 기법입니다. | ||
|
||
- **메모이제이션된 셀렉터 사용 (`createSelector`)**: | ||
- `createSelector`는 Redux Toolkit에 포함된 `reselect` 라이브러리의 일부로, 불필요한 계산을 방지하고 성능을 향상시킬 수 있습니다. | ||
- **사용 예시**: | ||
|
||
```jsx | ||
const selectItems = (state) => state.items; | ||
const selectFilter = (state) => state.filter; | ||
|
||
const selectFilteredItems = createSelector( | ||
[selectItems, selectFilter], | ||
(items, filter) => items.filter((item) => item.type === filter) | ||
); | ||
|
||
const filteredItems = useSelector(selectFilteredItems); | ||
|
||
``` | ||
|
||
- `createSelector`는 상태가 변경되지 않으면 이전에 계산된 결과를 반환하여, 불필요한 연산과 리렌더링을 방지할 수 있습니다. | ||
|
||
> **메모이제이션 (Memoiztion)** : | ||
컴퓨터 프로그램이 동일한 계산을 반복적으로 해야할 때, **이전에 계산한 값을 메모리에 저장**하여 **중복적인 계산을 제거**하여 전체적인 실행속도를 빠르게 해주는 기법입니다. | ||
> | ||
|
||
--- | ||
|
||
### **2. Redux Toolkit을 통한 효율적인 상태 관리** | ||
|
||
Redux Toolkit은 Redux의 공식 툴킷으로, 보일러플레이트 코드를 줄이고 일반적인 Redux 작업을 간소화합니다. 기본적으로 Immer와 Redux Thunk를 포함하고 있어, 불변성 관리와 비동기 작업 처리가 수월합니다. | ||
|
||
- **`createSlice`와 `createSelector` 사용**: | ||
- `createSlice`를 사용하면 상태와 리듀서를 간결하게 정의할 수 있으며, `createSelector`와 결합하여 효율적인 상태 관리와 성능 최적화를 할 수 있습니다. | ||
- **사용 예시**: | ||
|
||
```jsx | ||
const usersSlice = createSlice({ | ||
name: 'users', | ||
initialState: { list: [], status: 'idle' }, | ||
reducers: { | ||
addUser: (state, action) => { | ||
state.list.push(action.payload); | ||
}, | ||
}, | ||
}); | ||
const selectUsers = (state) => state.users.list; | ||
const selectActiveUsers = createSelector( | ||
[selectUsers], | ||
(users) => users.filter((user) => user.isActive) | ||
); | ||
``` | ||
|
||
- 이를 통해 불필요한 리렌더링과 성능 저하를 방지하며, 애플리케이션의 효율성을 높일 수 있습니다. | ||
|
||
--- | ||
|
||
### **3. 불변성 유지와 Immer의 활용** | ||
|
||
불변성을 유지하는 것은 Redux 성능 최적화에서 중요한 역할을 합니다. Redux Toolkit은 내부적으로 `Immer` 라이브러리를 사용하여 불변성을 자동으로 관리합니다. 이를 통해 상태를 직관적이고 간단하게 업데이트할 수 있습니다. | ||
|
||
- **불변성 유지**: | ||
- 불변성을 유지하면 상태 변화 추적이 용이하고, 예기치 않은 부작용을 방지할 수 있습니다. | ||
- **Redux Toolkit과 Immer**: | ||
- **사용 예시**: | ||
|
||
```jsx | ||
const todosSlice = createSlice({ | ||
name: 'todos', | ||
initialState: [], | ||
reducers: { | ||
addTodo: (state, action) => { | ||
state.push(action.payload); // Immer가 자동으로 불변성을 유지해줌 | ||
}, | ||
toggleTodo: (state, action) => { | ||
const todo = state.find(todo => todo.id === action.payload); | ||
if (todo) { | ||
todo.completed = !todo.completed; | ||
} | ||
}, | ||
}, | ||
}); | ||
``` | ||
|
||
- 이를 통해 명령형 프로그래밍 스타일로 상태를 쉽게 업데이트하면서도 불변성을 유지할 수 있습니다. | ||
|
||
> **Immer** : | ||
상태 변경 시 원본 상태를 복사한 후 변경된 부분만 업데이트하여 새로운 상태를 반환하는 불변성 관리 라이브러리입니다. | ||
직관적인 불변성 관리를 통해, 개발자가 실수로 원본 상태를 수정하는 것을 방지할 수 있습니다. | ||
> | ||
|
||
--- | ||
|
||
### **4. 미들웨어와 캐싱을 활용한 비동기 작업 최적화** | ||
|
||
비동기 작업을 처리할 때의 최적화 기법입니다. Redux Thunk를 사용하면 비동기 로직을 명확하게 관리할 수 있으며, 불필요한 API 호출을 줄이기 위해 캐싱을 활용할 수 있습니다. | ||
|
||
- **Redux Thunk의 활용**: | ||
- 비동기 작업을 관리하고, 필요한 시점에 상태를 업데이트할 수 있습니다. | ||
- **비동기 작업의 성능 최적화**: | ||
- 예를 들어, 동일한 데이터를 반복적으로 요청하는 대신, 한 번 요청한 데이터를 스토어에 저장하고 필요할 때마다 스토어에서 가져오는 방식으로 성능을 최적화할 수 있습니다. | ||
- **사용 예시**: | ||
|
||
```jsx | ||
const fetchUserById = (userId) => async (dispatch, getState) => { | ||
const cachedUser = getState().users.find(user => user.id === userId); | ||
if (cachedUser) { | ||
return; // 캐시된 데이터가 있으면 추가 API 호출을 방지 | ||
} | ||
const response = await fetch(`/api/users/${userId}`); | ||
const data = await response.json(); | ||
dispatch(usersSlice.actions.addUser(data)); | ||
}; | ||
``` | ||
|
||
- 이를 통해 비동기 작업이 성능에 미치는 영향을 최소화할 수 있습니다. | ||
|
||
--- | ||
|
||
## **결론** | ||
|
||
지금까지 리액트의 함수 컴포넌트에서 Redux를 사용할 때 적용할 수 있는 다양한 성능 최적화 기법을 살펴보았습니다. `useSelector`의 최적화, `createSelector`를 활용한 메모이제이션, 불변성 유지, 그리고 Redux Thunk를 통한 비동기 작업 최적화는 모두 애플리케이션의 성능과 사용자 경험을 크게 향상시킬 수 있는 중요한 기법들입니다. | ||
|
||
다양한 최적화 기법들을 상황에 맞게 적용하여, 보다 빠르고 안정적인 애플리케이션을 개발하시길 바랍니다. |