[React] 13-Redux

Jang·2022년 11월 9일
0

학원

목록 보기
25/26

리덕스

  • 리액트 전역 상태 관리 라이브러리

일반적인 컴포넌트 개발시에는 상태값(변수)을 관리하기 위해 라이프사이클이나 hooks을 사용한다.
이 경우 각각의 컴포넌트가 관리하는 변수값들이 소스파일 여기저기에 흩어져 있기 때문에 코드 유지보수에 좋지 않다.
컴포넌트의 상태 업데이트 관련 로직을 다른 파일로 분리시켜서 더욱 효율적으로 관리할 수 있다.
즉, 여러 개의 컴포넌트가 개별적으로 관리하는 상태값들을 하나의 소스에 모아 놓고 통합 관리하는 것이 목적.
컴포넌트끼리 상태를 공유해야 할 때도 여러 컴포넌트를 거치지 않고 손쉽게 상태 값을 전달하거나 업데이트할
수 있다.

리덕스 기본 요소

  • Slice

    • 리덕스에서 관리하고자 하는 상태값과 상태값 갱신 기능을 포함하는 단위 모듈
      1. 상태값 - 리덕스를 통해 관리하고자 하는 전역 상태값.
      2. 리듀서 - 상태값을 갱신하기 위한 함수(=액션함수)들을 포함하고 있는 모듈
      3. 액션함수 - 리듀서에 포함된 메서드들로서 상태값을 갱신하는 역할을 수행한다.
  • Store

    • Slice를 저장하고 있는 통합 모듈.
    • 이 모듈을 ReactApp의 메인(index.js)에 연결하여 모든 하위 컴포넌트들이 Redux가 관리하는 상태값을 구독할
      수 있도록 한다
  • Component

    • 리액트에서 화면을 구성하는 요소(지금까지 사용해온 컴포넌트를 의미)
      1. 구독 - 컴포넌트에서 리덕스 내의 상태값이 변경되었음을 감지하는 기능
      2. 디스패치 - 리덕스의 액션함수를 호출하는 기능

리덕스 미들웨어

  • 액션을 디스패치했을 때 리듀서에서 이를 처리하기에 앞서 실행되는 사전에 지정된 작업들.

    미들웨어로 수행하는 처리들

    전달받은 액션을 단순히 콘솔에 기록
     전달받은 액션 정보를 기반으로 액션을 아예 취소
     다른 종류의 액션을 추가로 디스패치
     비동기 액션 처리 등

    동작순서

    [사용자 이벤트] ――▶ [액션함수 디스패치] ――▶ [미들웨어 자동실행] ――▶ [리듀서의 액션함수 실행됨] ――▶ [액션값이 갱신됨]



React에 Redux 적용하기

1. Redux Store 준비하기

  • 상태값, 액션, 액션함수, 리듀서, 스토어가 통합된 형태

/src/store.js

// 폴더와 파일을 직접 생성해야 함.

import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
 // 개발자가 직접 작성한 Slice 오브젝트들이 명시되어야 한다.
 reducer: {
 ...
 }
});
export default store;

2. Redux Store를 React에 구독시키기

/src/index.js

// 리덕스를 위한 참조 추가
/** 리덕스 구성을 위한 참조 */
import { Provider } from 'react-redux';
import store from './store';

// 렌더링 처리
// 렌더링 처리를 <Provider store={store}> 태그로 감싼다.
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
 <Provider store={store}>
 <BrowserRouter>
 <App />
 </BrowserRouter>
 </Provider>
);

3. Slice 모듈 작성

/src/slices/slice이름.js

동기처리인 경우 (Ajax 사용 안하는 경우) reducers

import { createSlice } from '@reduxjs/toolkit'
const slice이름 = createSlice({
 name: 'slice이름',
 // 이 모듈이 관리하고자하는 상태값들을 명시
 initialState: {
 변수1: 100,
 변수2: 200
 },
 // 상태값을 갱신하기 위한 함수들을 구현
 // 컴포넌트에서 이 함수들을 호출할 때 전달되는 파라미터는 action.payload로 전달된.
 // initialState와 동일한 구조의 JSON을 리턴한다.
 reducers: {
 액션함수1: (state, action) => {...state},
 액션함수2: (state, action) => {...state}
 }
});
// 액션함수들 내보내기
export const { 액션함수1, 액션함수2 } = slice이름.actions;
// 리듀서 객체 내보내기
export default slice이름.reducer;

비동기처리인 경우 (Ajax를 사용하는 경우) extraReducers

  import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
  import axios from 'axios';

  const API_URL = '...';

  /** Ajax처리를 위한 미들웨어 함수 정의 */
  export const 함수이름 = createAsyncThunk("slice이름/함수이름", async (payload, {
  rejectWithValue }) => {
     let result = null;

     try {
     result = await axios.get|post|put|delete(API_URL);
     } catch (err) {
     result = rejectWithValue(err.response);
     }

     return result;
  });

  const slice이름 = createSlice({
     name: 'slice이름',
     // 이 모듈이 관리하고자하는 상태값들을 명시
     initialState: {
         data: null,
         loading: false,
         error: null
     },
     // 상태값을 갱신하기 위한 함수들을 구현
     // Ajax의 처리 과정에 따라 자동으로 실행된다.
     extraReducers: {
       // 로딩중임을 표시
       [함수이름.pending]: (state, { payload }) => {
         return { ...state, loading: true }
       },
       // 처리가 완료된 경우 - 미들웨어 함수가 정상적으로 리턴한 경우
       [함수이름.fulfilled]: (state, { payload }) => {
         return {
             data: payload?.data,
             loading: false,
             error: null
         }
       },
       // 처리에 실패한 경우 - 미들웨어 함수 안에서 예외가 발생하여 catch블록이 실행된 경우
       [함수이름.rejected]: (state, { payload }) => {
         return {
             data: payload?.data,
             loading: false,
             error: {
                 code: payload?.status ? payload.status : 500,
                 message: payload?.statusText ? payload.statusText : 'Server Error'
             }
         }
       }
     },
  });
  export default Slice파일이름.reducer;

4. 정의한 Slice 모듈 명시

/src/slice/store.js

import { configureStore } from '@reduxjs/toolkit';
import slice이름 from './slices/slice이름';
const store = configureStore({
 // 개발자가 직접 작성한 Slice 오브젝트들이 명시되어야 한다.
 reducer: {
 slice이름: slice이름,
 ...
 },
 // 비동기 미들웨어 추가 (Ajax처리가 필요한 경우만 설정)
 middleware: (getDefaultMiddleware) => getDefaultMiddleware({serializableCheck:
false}),
});
export default store;

5. 컴포넌트에서 사용하기

  1. 필요한 기능 참조하기

    // 상태값을 로드하기 위한 hook과 action함수를 dispatch할 hook 참조
    import { useSelector, useDispatch } from 'react-redux'
    // Slice에 정의된 함수 참조
    // - 동기처리인 경우에는 리듀서 내의 액션함수 참조
    // - 비동기 처리인 경우에는 Slice 내의 미들웨어 함수 참조
    import { 함수1, 함수2 } from '../slices/slice이름';
  2. 컴포넌트 내부에서 hook을 통해 필요한 Object 생성

    // hook을 통해 slice가 관리하는 상태값 가져오기
    const {변수1, 변수2} = useSelector((state) => state.slice이름);
    // dispatch 함수 생성
    const dispatch = useDispatch();
  3. 필요한 이벤트 핸들러 안에서 액션함수 디스패치하기

    • Slice에서 정의한 액션함수의 action.payload 파라미터로 전달된다. 다수의 파라미터가 필요한 경우 JSON객체로 묶어서 전달한다.
    dispatch(함수1(파라미터));
    dispatch(함수2(파라미터));

0개의 댓글