250x250
Notice
Recent Posts
Recent Comments
Link
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Archives
Today
Total
관리 메뉴

y.developer

[TIL] Day 45 reducers와 extrareducers (Thunk) 본문

카테고리 없음

[TIL] Day 45 reducers와 extrareducers (Thunk)

y.developer 2023. 12. 6. 23:28
728x90

2023.12.06 수

 

Thunk의 주요 개념 살펴보기

  1. Redux toolkit에 내장되어 있는 기능
  2. 미들웨어
  3. dispatch 시, 객체가 아닌 함수를 dispatch
  4. 비동기 통신 처리

 

1. RTK(Redux Toolkit)에 내장되어 있는 기능이다.

Redux Toolkit은 Redux Thunk를 기본 미들웨어로 포함하고 있어 별도의 설치가 필요하지 않다.

 

2. 미들웨어이다.

Redux Thunk는 Redux 미들웨어로 작동한다.

이는 액션을 보내기 전과 후에 추가적인 로직을 실행할 수 있게 해 줍니다.

 

3. 함수를 dispatch 할 수 있다.

기본적으로 Redux는 객체 형태의 액션만을 dispatch 할 수 있다.

하지만 Redux Thunk를 사용하면 함수를 dispatch할 수 있게 되어, 이 함수 내에서 비동기 로직을 처리하고 결과에 따라 다른 액션을 dispatch할 수 있다.

여기서 주의할 점! 결국 우리의 목적은 dispatch를 통해 ‘전역 데이터를 세팅’하는 데에 있다는 것이다.

 

json-server 설정(+db.json)

{
  "todos": [
		{ "id": 1, "title": "hello world!" },
		{ "id": 2, "title": "hello Javascript!" },
		{ "id": 3, "title": "hello React!" },
	]
}

 

src/redux/modules/todosSlice.js

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

const initialState = {
  todos: [],
  isLoading: false,
  error: null,
};

export const __getTodos = createAsyncThunk(
  "todos/getTodos",
  async (payload, thunkAPI) => {
    try {
      const data = await axios.get("http://localhost:3001/todos");
      return thunkAPI.fulfillWithValue(data.data);
    } catch (error) {
      return thunkAPI.rejectWithValue(error);
    }
  }
);

export const todosSlice = createSlice({
  name: "todos",
  initialState,
  reducers: {},
  extraReducers: {
    [__getTodos.pending]: (state) => {
      state.isLoading = true; // 네트워크 요청이 시작되면 로딩상태를 true로 변경합니다.
    },
    [__getTodos.fulfilled]: (state, action) => {
      state.isLoading = false; // 네트워크 요청이 끝났으니, false로 변경합니다.
      state.todos = action.payload; // Store에 있는 todos에 서버에서 가져온 todos를 넣습니다.
    },
    [__getTodos.rejected]: (state, action) => {
      state.isLoading = false; // 에러가 발생했지만, 네트워크 요청이 끝났으니, false로 변경합니다.
      state.error = action.payload; // catch 된 error 객체를 state.error에 넣습니다.
    },
  },
});

export const {} = todosSlice.actions;
export default todosSlice.reducer;

 

src/App.jsx

// src/App.jsx

import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { __getTodos } from "./redux/modules/todosSlice";

const App = () => {
  const dispatch = useDispatch();
  const { isLoading, error, todos } = useSelector((state) => state.todos);

  useEffect(() => {
    dispatch(__getTodos());
  }, [dispatch]);

  if (isLoading) {
    return <div>로딩 중....</div>;
  }

  if (error) {
    return <div>{error.message}</div>;
  }

  return (
    <div>
      {todos.map((todo) => (
        <div key={todo.id}>{todo.title}</div>
      ))}
    </div>
  );
};

export default App;

 

reducers vs extraReducers

createSlice API를 이용해서 slice를 만든다.

slice를 만들 때 우리는 다음 내용을 필요로 한다.

 

  1. name
  2. initialState
  3. reducers
  4. extraReducers

 

일반적인 전역상태를 관리할 때는 reducers를 사용하고, 비동기 통신 등에는 extraReducers를 사용한다.

결국, createSlice에 의해 자동으로 생성된 action creator로 인해 접수된 변경 건은 reducers 부분에서 처리한다.

그리고 자동으로 처리될 수 없는 즉, 외부에서부터 정의된 이름으로 생성되고 정의되는 createAsyncThunk 등을 사용하는 외부 action은 reducers에서 처리할 수 없으므로 extraReducers에서 처리하는 것이다.

 

reducers

- 동기적 액션 처리

reducers는 주로 동기적인 액션을 처리하는 데 사용된다.

여기서는 애플리케이션의 상태를 직접적으로 업데이트하는 동기 액션 핸들러들을 정의한다.


- 액션 타입 생성

createSlice 함수는 reducers 객체에 정의된 각 메서드에 대해 자동으로 액션 타입을 생성한다.

이 액션 타입은 리듀서 함수의 이름을 기반으로 한다.


- 직관적인 사용

reducers에서 정의된 액션 핸들러는 액션 객체를 인자로 받아, 새로운 상태를 반환한다.

이는 전통적인 Redux 패턴을 따르며, 비교적 이해하기 쉽다.

 


extraReducers

- 비동기적 액션 및 외부 액션 처리

extraReducers는 주로 비동기 액션 또는 슬라이스 외부에서 발생하는 액션을 처리하는 데 사용된다.

이는 createAsyncThunk로 생성된 액션 또는 다른 슬라이스/라이브러리에서 발생한 액션을 처리할 때 유용하다.


- 액션 타입에 대한 명시적 매핑

extraReducers에서는 액션 타입을 직접 지정해야 한다.

이는 Redux Toolkit이 createAsyncThunk를 사용하여 생성된 비동기 액션들에 대해 세 가지 상태별 액션 타입(pending, fulfilled, rejected)을 자동으로 생성하기 때문에 중요하다.


- 비동기 작업의 복잡성 관리

비동기 작업은 다양한 상태(로딩 중, 완료, 에러)를 갖기 때문에, extraReducers를 사용하면 이러한 상태에 따른 다양한 처리를 효율적으로 관리할 수 있다.

예를 들어, createAsyncThunk를 사용한 경우, 각 비동기 작업의 시작, 성공, 실패 상태별로 다른 액션을 처리할 수 있다.

 

 

아래 예시코드를 참조해 볼 때,

결국 동일한 state를 reducers와 extraReducers가 변경하기 위해 관여한다는 것을 알 수 있다.

const todosSlice = createSlice({
  name: 'todos',
  initialState,
  reducers: {
    // 동기적 액션 핸들러
    addTodo: (state, action) => {
      // 직접 상태를 업데이트
    },
  },
  extraReducers: {
    // 비동기 액션 핸들러
    [__getTodos.pending]: (state, action) => {
      // 로딩 상태 처리
    },
    [__getTodos.fulfilled]: (state, action) => {
      // 요청 성공 시 상태 처리
    },
    [__getTodos.rejected]: (state, action) => {
      // 에러 상태 처리
    },
  },
});

 

 

4. 비동기 통신에 사용

Redux Thunk는 API 호출과 같은 비동기 작업을 처리하는 데 자주 사용된다.

이를 통해 애플리케이션의 상태를 비동기적으로 업데이트할 수 있다.

 

 

+ extraReducers의 변화

extraReducers가 삭제된 것이 아닌 extraReducer를 구현할 때 object notation 문법 호환 기능을 삭제했다고 한다.

redux toolkit 최신버전부터는 [__thunk.pending] 과 같은 문법은 허용이 안되니, "yarn add @reduxjs/tookit@1.9.7"로 버전을 낮춰서(다운그레이드) 작업을 진행하거나, 바뀐 로직 빌더 콜백함수를 이용한 extraReducers (builder,addCase 등)(아래 링크 참고)로 작성해야 한다.

최근 많이 사용되고 있는 React Query를 사용하는 방법이 가장 이상적인 것 같다.

 

https://redux.js.org/tutorials/essentials/part-5-async-logic

 

Redux Essentials, Part 5: Async Logic and Data Fetching | Redux

The official Redux Essentials tutorial: learn how async logic works in Redux apps

redux.js.org

 

https://tak-web-front.tistory.com/37#comment15271704

 

[에러일지] createSlice.ts:335 The object notation for `createSlice.extraReducers` is deprecated, and will be removed in RTK

redux-thunk 강의를 듣던중 위와같은 워닝 에러가 떴다 에러 분석 번역 createSlice.extraReducers'의 개체 표기법은 사용되지 않으며 RTK 2.0에서 제거됩니다. 대신 '빌더 콜백' 표기법을 사용하십시오 redux-t

tak-web-front.tistory.com

 

 

 


하루를 마치며

어제 Thunk와 extraReducers를 사용해서 로직을 작성하는 연습을 진행했는데 계속 에러나 났었다.

찾아본 결과 버전과 관련된 에러였는데, 최신 버전인데 왜 에러가 나는지 의문이었다.

그러나 오히려 최신 버전이어서 작동을 하지 않은 것이었다!!

extraReducers의 사용 방법이 바뀌었을 거라곤 생각도 못했다. 역시 변화가 빠른 프론트엔드인 것 같다.

바뀐 로직인 빌더 콜백함수를 이용한 extraReducers를 작성하는 것보다, 많은 사람들이 사용하고 있고 트렌드로 자리를 잡고 있는 React Query로 작성하는 것이 더 좋겠다.

 

 

오늘의 한 줄
빠르게 변화하는 세상을 앞서갈 순 없지만,
부단히 따라갈 순 있다.

 

 

 

 

728x90