React/Redux 마스터

Redux Toolkit 활용(3강): 성능 최적화

atomicdev 2024. 10. 21. 15:40
728x90

3. 성능 최적화: Zustand와 Redux Toolkit 비교

상태 관리에서 성능 최적화는 특히 큰 규모의 애플리케이션에서 중요한 요소입니다. 상태 변경에 따른 불필요한 리렌더링을 줄이는 것은 애플리케이션의 응답성을 높이고 사용자 경험을 향상시키는 데 필수적입니다.

안녕하세요! 이번 포스팅에서는 Redux ToolkitZustand의 성능 차이, 특히 리렌더링 문제와 이를 해결하는 방법에 대해 다루어보겠습니다. 또한, Redux Toolkit을 사용하여 성능을 최적화하는 Todo 리스트 앱을 실습해 보겠습니다. 이 과정을 통해 상태 관리에서 성능을 어떻게 개선할 수 있는지 자세히 알아보세요.

Redux Toolkit과 Zustand의 성능 비교

Redux와 Zustand의 성능 차이

Redux와 Zustand는 둘 다 전역 상태를 관리할 수 있는 라이브러리입니다. 하지만 성능과 사용성 측면에서 몇 가지 차이점이 있습니다.

  • Zustand는 더 간단하고 가벼운 상태 관리 솔루션입니다. 예를 들어, 작은 규모의 애플리케이션에서는 간단한 전역 상태 관리를 위해 Redux보다 설정이 적고 사용이 쉬운 Zustand를 사용하는 것이 더 효율적일 수 있습니다. Zustand는 전역 상태를 변경할 때 불필요한 리렌더링이 발생하지 않도록 최적화되어 있어 성능 면에서 이점을 제공합니다. 불필요한 상태 업데이트를 줄이는 방식으로 구성되어 있어, 자연스럽게 성능 저하를 방지합니다.
  • Redux는 전역 상태를 관리하는 데에 강력한 도구이지만, 전역 상태 변경 시 모든 컴포넌트가 리렌더링될 가능성이 높습니다. 이는 전역 상태가 변경될 때 해당 상태와 관련 없는 컴포넌트들까지 리렌더링되는 경우가 많기 때문입니다. 특히 큰 규모의 애플리케이션에서는 이러한 불필요한 리렌더링이 성능 저하를 초래할 수 있습니다. 이는 성능 저하의 원인이 될 수 있습니다. 특히 Redux의 경우 모든 상태를 한 곳에서 관리하기 때문에, 상태 변경 시 필요하지 않은 컴포넌트까지 리렌더링되는 일이 발생할 수 있습니다.

이러한 Redux의 성능 문제를 해결하기 위해 Redux ToolkituseSelector를 사용해 필요한 상태만 구독하게 하고, React.memo를 통해 불필요한 컴포넌트 리렌더링을 방지할 수 있습니다. useSelector는 특정 상태만 선택하여 구독함으로써 필요하지 않은 상태 변경이 다른 컴포넌트에 영향을 주지 않도록 하고, React.memo는 컴포넌트의 props가 변경되지 않는 한 리렌더링을 막아 성능을 최적화합니다. 이 방법들을 통해 Redux에서의 성능 문제를 크게 줄일 수 있습니다.

실습: Todo 리스트 예제 만들기

이번 실습에서는 Todo 리스트 앱을 구현하면서 성능 최적화의 개념을 실습해 보겠습니다. 이 Todo 리스트 예제는 상태 구독과 컴포넌트 리렌더링을 최적화하여 성능을 개선하는 방법을 이해하는 데 도움을 줄 것입니다.

이번 실습에서는 Redux ToolkitReact.memo를 사용해 성능 최적화된 Todo 리스트 앱을 구현해 보겠습니다. 이 예제는 상태 구독 최적화컴포넌트 리렌더링 최적화에 중점을 둡니다.

1. Todo 항목 추가/삭제 기능 구현하기

먼저, createSlice를 사용하여 Todo 상태를 관리할 슬라이스를 정의하고, Todo 항목을 추가 및 삭제하는 기능을 구현하겠습니다.

// src/app/store.js
import { configureStore } from '@reduxjs/toolkit';
import todoReducer from '../features/todo/todoSlice';

export const store = configureStore({
  reducer: {
    todo: todoReducer,
  },
});
// src/features/todo/todoSlice.js
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
  todos: [], // 초기 상태를 빈 배열로 설정
};

const todoSlice = createSlice({
  name: 'todo',
  initialState,
  reducers: {
    addTodo: (state, action) => {
      state.todos.push({ id: Date.now(), text: action.payload });
    },
    removeTodo: (state, action) => {
      state.todos = state.todos.filter((todo) => todo.id !== action.payload);
    },
  },
});

export const { addTodo, removeTodo } = todoSlice.actions;
export default todoSlice.reducer;

위 코드에서는 addTodoremoveTodo 액션을 사용해 Todo 항목을 추가하고 삭제할 수 있습니다. createSlice를 사용하면 리듀서와 액션을 한 번에 정의할 수 있어 코드가 간결해지고, 유지보수가 용이해집니다. createSlice를 사용해 리듀서와 액션을 정의함으로써 코드가 간결하고 유지보수가 용이해졌습니다.

2. useSelector로 필요한 상태만 구독하기

useSelector를 사용하여 Redux 상태에서 필요한 부분만 선택해 컴포넌트에서 구독할 수 있습니다. 예를 들어, Todo 리스트 상태만 구독하면 Todo와 관련 없는 다른 상태 변경이 발생할 때 해당 컴포넌트가 리렌더링되지 않습니다. 이를 통해 불필요한 렌더링을 줄여 성능을 개선할 수 있습니다. 이를 통해 불필요한 리렌더링을 줄일 수 있습니다.

// src/components/TodoList.js
import React, { memo } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { removeTodo } from '../features/todo/todoSlice';

const TodoList = memo(() => {
  const todos = useSelector((state) => state.todo.todos); // 정확한 상태 경로 확인
  const dispatch = useDispatch();

  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>
          {todo.text}
          <button onClick={() => dispatch(removeTodo(todo.id))}>Delete</button>
        </li>
      ))}
    </ul>
  );
});

export default TodoList;

위 코드에서는 useSelector를 사용하여 todos 상태만 구독하고, React.memo를 사용하여 TodoList 컴포넌트의 불필요한 리렌더링을 방지합니다. React.memo는 컴포넌트의 props가 변경되지 않는 한 해당 컴포넌트를 리렌더링하지 않습니다. 이를 통해 불필요한 렌더링을 방지하고 성능을 최적화할 수 있습니다. 이렇게 하면 Todo 리스트 상태가 변경되지 않는 한 TodoList 컴포넌트는 다시 렌더링되지 않아 성능이 최적화됩니다.

3. Todo 항목 추가 컴포넌트

이제 Todo 항목을 추가하는 기능을 가진 컴포넌트를 만들어 보겠습니다.

AddTodo 컴포넌트에서는 사용자의 입력을 받아 Todo 항목을 추가하는 기능을 수행합니다. useDispatch를 사용하여 addTodo 액션을 디스패치합니다.

// src/components/AddTodo.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { addTodo } from '../features/todo/todoSlice';

function AddTodo() {
  const [text, setText] = useState('');
  const dispatch = useDispatch();

  const handleSubmit = (e) => {
    e.preventDefault();
    if (text.trim()) {
      dispatch(addTodo(text));
      setText('');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Add a new todo"
      />
      <button type="submit">Add</button>
    </form>
  );
}

export default AddTodo;

4. App.js에서 컴포넌트 통합하기

이 단계에서는 AddTodoTodoList 컴포넌트를 App 컴포넌트에 통합하여 완전한 기능을 갖춘 Todo 리스트 애플리케이션을 구축합니다. 이를 통해 사용자는 Todo 항목을 추가하고 삭제할 수 있으며, 애플리케이션의 상태를 손쉽게 관리할 수 있습니다.

마지막으로, AddTodoTodoList 컴포넌트를 App.js에 통합하여 Todo 리스트 애플리케이션을 완성합니다.

App 컴포넌트에서 AddTodoTodoList를 렌더링하여 전체 Todo 리스트 애플리케이션이 구성되었습니다. 이를 통해 사용자에게 Todo 항목 추가 및 삭제 기능을 제공합니다.

// src/App.js
import React from 'react';
import AddTodo from './components/AddTodo';
import TodoList from './components/TodoList';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <h1>Todo List</h1>
        <AddTodo />
        <TodoList />
      </header>
    </div>
  );
}

export default App;

Todo List 실행화면

핵심 학습 내용

  • Redux와 Zustand의 성능 차이: Redux는 전역 상태 변경 시 불필요한 리렌더링이 발생할 수 있는 반면, Zustand는 이를 최소화하여 성능을 개선합니다.
  • Redux Toolkit의 성능 최적화 도구: useSelectorReact.memo를 사용하여 필요한 상태만 구독하고, 컴포넌트의 불필요한 리렌더링을 방지할 수 있습니다.
  • Todo 리스트 예제 실습: Todo 항목 추가 및 삭제 기능을 구현하면서 성능 최적화를 적용해 보았습니다.
  • 상태 구독 최적화: useSelector를 사용해 특정 상태만 구독함으로써 불필요한 리렌더링을 줄였습니다.
  • 컴포넌트 리렌더링 방지: React.memo를 사용해 props가 변경되지 않는 한 컴포넌트를 리렌더링하지 않도록 최적화했습니다.

이번 포스팅에서는 Redux ToolkitZustand의 성능 차이에 대해 알아보고, Redux의 성능 문제를 해결하는 방법을 실습해 보았습니다. useSelector로 필요한 상태만 구독하고, React.memo를 사용하여 컴포넌트의 불필요한 리렌더링을 방지함으로써 성능을 최적화할 수 있습니다.

이러한 성능 최적화는 특히 큰 규모의 애플리케이션에서 중요한데, 상태 변경에 따른 불필요한 리렌더링을 줄이는 것이 사용자 경험을 향상시키는 핵심 요소가 됩니다. 다음 강의에서는 비동기 상태 관리와 관련된 최적화 방법에 대해 다뤄보겠습니다.

Redux Toolkit을 사용하여 상태 관리에서 발생하는 성능 문제를 해결하고, 더 나은 React 애플리케이션을 만들어 보세요!

728x90