21.07.30 Redux-Toolkit (2)

김정후·2021년 8월 3일
0

TIL

목록 보기
35/37

컴포넌트에서 state와 action 사용하기

React Hooks를 사용하여 react-redux의 useSelector와 useDispatch로 간단하게 state와 action에 접근할 수 있다.

useSelector

import {RootState, useAppDispatch} from '../reducers';
import {setSearchValue} from '../reducers/todoSlice';
...

const dispatch = useAppDispatch();
....
    dispatch(addTodo({id:1, text:'Redux-toolkit을 활용한 상태관리'}));
...

useDispatch

import {RootState} from '../reducers';

const todos = useSelector((state: RootState) => state.todos);

비동기 처리하기

redux store 자체적으로는 비동기 처리를 하지 못하기 때문에 redux-thunk, redux-saga, redux-observable 등과 같은 미들웨어를 사용해서 비동기 액션 처리를 해야 한다. 공식 문서에서는 Redux Thunk를 사용하는 것을 추천하며, 이전에 언급했듯이 configureStore 함수는 기본적으로 thunk 미들웨어를 포함하고 있으므로 따로 설정해 주지 않더라도 바로 사용이 가능하다

createAsyncThunk

createAsyncThunk API로 비동기 액션을 만들면 이 액션에 대해 pending, fulfilled, rejected 상태에 대한 액션이 자동으로 생성된다. 먼저 비동기 액션은 아래와 같이 생성한다.

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

interface MyKnownError {
  errorMessage: string
}

interface TodosAttributes {
  id: number;
  text: string;
  completed: boolean
}

export const fetchTodos = createAsyncThunk<
  TodosAttributes[], // 성공 시 리턴 타입
  number, // input type
  { rejectValue: MyKnownError } // thunkApi 정의({dispatch?, state?, extra?, rejectValue?})
>('todos/fetchTodos', async(userId, thunkAPI) => {
  try { 
    const {data} = await axios.get(`https://localhost:3000/todos/${userId}`);
    return data;
  } catch(e){
    return rejectWithValue({ errorMessage: '알 수 없는 에러가 발생했습니다.' });
  }
})

만들어진 비동기 액션에 대한 리듀서는 아래와 같이 extraReducers로 작성할 수 있다. extraReducers로 지정된 reducer는 외부 작업을 참조하기 위한 것이기 때문에 slice.actions에 생성되지 않는다. 또한, ActionReducerMapBuilder를 수신하는 콜백으로 작성하는 것이 권장된다.

interface ITodoState {
  loading: boolean;
  error: null | string;
  todos: TodosAttributes[]
}

const initialState:ITodoState = {
  loading: false,
  error: null,
  todos: []
}

const todosSlice = createSlice({
  name: 'todos',
  initialState,
  reducers: {
    ...
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchTodos.pending, (state) => {
        state.error = null;
        state.loading = true;
      })
      .addCase(fetchTodos.fulfilled, (state, { payload }) => {
        state.error = null;
        state.loading = false;
        state.todos = payload;
      })
      .addCase(fetchTodos.rejected, (state, { payload }) => {
        state.error = payload;
        state.loading = false;
      });
  },
})
profile
리엑트 두두등장

0개의 댓글