React/Redux 마스터

Redux Toolkit 활용 실습(3): React와 Redux의 호환성 개선

atomicdev 2024. 10. 24. 15:04
728x90

React와 Redux의 호환성 개선하기

이번 포스팅에서는 ReactRedux 간의 호환성을 개선하는 방법을 알아보겠습니다. 특히 createSlice, createAsyncThunk, useSelector, useDispatch 같은 기능을 사용하여 컴포넌트와 Redux의 상호작용을 간소화하고 성능을 최적화하는 방법을 Before -> After 형식으로 설명합니다.

1. 호환성 개선의 필요성

React와 Redux를 함께 사용할 때 자주 발생하는 문제는 컴포넌트의 불필요한 리렌더링과 상태 구독의 비효율성입니다. 이러한 문제들은 성능을 저하시킬 뿐만 아니라 유지보수를 어렵게 만듭니다. Redux Toolkit의 다양한 기능들을 사용하여 이러한 문제를 어떻게 해결할 수 있는지 살펴보겠습니다.

 

Before: 기존 Redux 방식의 호환성 문제

기존 Redux를 사용하여 React와 통합할 때는 다음과 같은 문제가 발생할 수 있습니다.

  1. 복잡한 액션과 리듀서 설정 React 컴포넌트에서 상태 관리를 위해 여러 파일에서 액션과 리듀서를 작성해야 합니다.
    // src/reducers/userReducer.js
    const initialState = {
      user: null,
    };
    
    const userReducer = (state = initialState, action) => {
      switch (action.type) {
        case 'LOGIN_USER':
          return {
            ...state,
            user: action.payload,
          };
        case 'LOGOUT_USER':
          return {
            ...state,
            user: null,
          };
        default:
          return state;
      }
    };
    
    export default userReducer;
  2. connect를 사용한 컴포넌트와 Redux 연결 React 컴포넌트를 Redux 스토어에 연결하기 위해 connect 함수를 사용해야 했습니다. 이는 코드가 길어지고 가독성을 떨어뜨립니다.
    // src/components/UserProfile.js
    import React from 'react';
    import { connect } from 'react-redux';
    import { loginUser, logoutUser } from '../actions/userActions';
    
    function UserProfile({ user, loginUser, logoutUser }) {
      return (
        <div>
          {user ? (
            <div>
              <h2>Welcome, {user.name}!</h2>
              <button onClick={logoutUser}>Logout</button>
            </div>
          ) : (
            <button onClick={() => loginUser({ name: 'John Doe', email: 'john.doe@example.com' })}>Login</button>
          )}
        </div>
      );
    }
    
    const mapStateToProps = (state) => ({
      user: state.user,
    });
    
    const mapDispatchToProps = {
      loginUser,
      logoutUser,
    };
    
    export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);

After: Redux Toolkit을 사용한 호환성 개선

Redux Toolkit을 사용하여 React와 Redux 간의 호환성을 어떻게 개선할 수 있는지 살펴보겠습니다.

  1. React 애플리케이션 생성 및 Redux Toolkit 설치 먼저 Redux Toolkit을 사용할 애플리케이션을 생성하고 필요한 패키지를 설치합니다.
    npx create-react-app my-redux-toolkit-app
    cd my-redux-toolkit-app
    npm install @reduxjs/toolkit react-redux

  2. createSlice와 createAsyncThunk로 상태 관리 간소화 createSlice를 사용하여 리듀서와 액션을 한 번에 정의하고, createAsyncThunk를 사용하여 비동기 작업을 간단하게 처리합니다.
    // src/features/user/userSlice.js
    import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
    
    export const fetchUser = createAsyncThunk('user/fetchUser', async (userId) => {
      const response = await fetch(`/api/user/${userId}`);
      return response.json();
    });
    
    const userSlice = createSlice({
      name: 'user',
      initialState: {
        user: null,
        status: 'idle',
      },
      reducers: {
        login: (state, action) => {
          state.user = action.payload;
        },
        logout: (state) => {
          state.user = null;
        },
      },
      extraReducers: (builder) => {
        builder
          .addCase(fetchUser.pending, (state) => {
            state.status = 'loading';
          })
          .addCase(fetchUser.fulfilled, (state, action) => {
            state.status = 'succeeded';
            state.user = action.payload;
          })
          .addCase(fetchUser.rejected, (state) => {
            state.status = 'failed';
          });
      },
    });
    
    export const { login, logout } = userSlice.actions;
    export default userSlice.reducer;
  3. useSelector와 useDispatch로 Hook 기반 통합 useSelectoruseDispatch를 사용하여 컴포넌트에서 Redux 상태를 쉽게 접근하고 액션을 디스패치할 수 있습니다. 이는 connect보다 코드가 간결하고 직관적입니다.useSelector를 통해 필요한 상태만 구독하고, useDispatch로 액션을 디스패치함으로써 코드의 가독성과 유지보수가 용이해집니다.
    // src/components/UserProfile.js
    import React from 'react';
    import { useSelector, useDispatch } from 'react-redux';
    import { login, logout } from '../features/user/userSlice';
    
    function UserProfile() {
      const user = useSelector((state) => state.user.user);
      const dispatch = useDispatch();
    
      const handleLogin = () => {
        const userInfo = { name: 'John Doe', email: 'john.doe@example.com' };
        dispatch(login(userInfo));
      };
    
      const handleLogout = () => {
        dispatch(logout());
      };
    
      return (
        <div>
          {user ? (
            <div>
              <h2>Welcome, {user.name}!</h2>
              <button onClick={handleLogout}>Logout</button>
            </div>
          ) : (
            <button onClick={handleLogin}>Login</button>
          )}
        </div>
      );
    }
    
    export default UserProfile;

    React와 Redux의 호환성 개선

 

세부 절차 및 전체 소스 확인

요약

  • 기존 방식: 여러 파일에 분산된 액션과 리듀서, connect를 사용한 컴포넌트 연결로 인해 코드가 복잡해지고 유지보수가 어려웠습니다.
  • Redux Toolkit 방식: createSlicecreateAsyncThunk를 사용하여 코드의 복잡성을 줄이고, useSelectoruseDispatch를 사용하여 React와 Redux를 더욱 자연스럽게 통합할 수 있었습니다.

실습 코드 요약

  • 기존 방식에서 발생할 수 있는 복잡한 코드 문제를 Redux Toolkit의 다양한 도구들을 사용하여 간소화할 수 있었습니다.
  • 이러한 도구들을 사용하면 코드가 더 간결해지고, React와 Redux의 호환성이 향상되어 유지보수가 쉬워집니다.
728x90