- 코딩알려주는누나 - 옛날 리덕스를 최신 리덕스 Toolkit으로 바꿔보자!
https://youtu.be/UKnLwVm9suY- Redux Toolkit 개념 정리 블로그
http://blog.hwahae.co.kr/all/tech/tech-tech/6946/- Redux Toolkit createApi() 공식문서
https://redux-toolkit.js.org/rtk-query/api/createApi
redux toolkit에 대한 강의는 여러개 찾아서 듣고 있지만
아직까지는 개념 숙지가 덜된 것 같아서 따로 개념을 정리하고자 합니다.
let initialState = {
productList: [],
selectedItem: null,
};
function productReducer(state = initialState, action) {
let { type, payload } = action;
switch (type) {
case "GET_PRODUCT_SUCCESS":
return { ...state, productList: payload.data };
case "GET_SINGLE_PRODUCT_SUCCESS":
return { ...state, selectedItem: payload.data };
default:
return { ...state};
}
}
export default productReducer;
import { createSlice } from '@reduxjs/tookit";
let initialState = {
productList: [],
selectedItem: null,
};
const productSlice = createSlice({
name: "product",
initialState,
reducers: {
getAllProducts(state, action) {
state.productList = action.payload.data;
},
getSingleProduct(state, action) {
state.selectedItem = action.payload.data;
},
},
});
export default productSlice.reducer;
createSlice()는 Reducer를 만드는 걸 도와줍니다.
인자로 객체를 받는데 그 객체는 name/initialState/reducers를 필수적으로 포함해야합니다.
createAction ❌, createReducer ❌
createAction, createReducer 함수가 내부적으로 사용되며 createSlice에 선언된 슬라이스 이름을 따라서 리듀서와 그리고 그것에 상응하는 액션 생성자와 액션 타입을 자동으로 생성합니다. 따라서 createSlice를 사용하면 따로 createAction, createReducer를 작성할 필요가 없습니다.
reducer { ...state, } ❌
기존코드에서는 switch문에서 항상 return을 필수적으로 해야했고, 원래있던 state값은 유지하되 거기에서 원하는 부분만 바꿀때는 { ...state, }
이 문법을 작성해야했습니다. 지금은 return할 필요도 없어졌고 계속 반복해서 ...state를 작성할 필요가 없어졌습니다.
export
reducers에 만든 모든 함수들이 자동으로 reducer로 묶어지기때문에
export 할 때 XXX.reducer
마지막에는 결국 하나의 큰 리듀서이기때문에 s를 붙이지않습니다.
import { createStore, applyMiddleWare } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
let store = createStore(
rootReducer,
composeWithDevTools(applyMiddleWare(thunk))
);
export default store;
이 네가지를 기본으로 항상 써야했습니다.
import { configureStore } from "@reduxjs/toolkit";
let store = configureStore({
reducer: {
auth: authenticateReducer,
product: productReducer,
},
});
export default store;
redux가 버전 업그레이드되면서 기존에 사용했던 createStore()대신 configureStore()를 사용하도록 권장하고있습니다.
configureStore()는 위에서 언급한 4가지를 모두 자동으로 커버해주기때문에 사용할 필요가 없습니다.
configureStore에 전달하는 객체 내부에
reducer:에 객체{} 를 통해 필요한 reducer를 바로 넣으면 됩니다.
위에서 reducer를 만들 때
switch문과 "GET_PRODUCT_SUCCESS"를 사용하지않고
getAllProducts(state, action) 이런식으로 함수를 정의했습니다.
그러면 Action을 호출할 때 type에 뭘 입력할지?? 에 대한 의문이 생깁니다.
function getProducts(searchQuery) {
return async (dispatch, getState) => {
let url = ``'
let response = await fetch(url);
let data = await response.json();
dispatch({type: "GET_PRODUCT_SUCCESS", payload: {data}});
};
}
export const productActions = productSlice.actions;
createSlice가 만든 유니크한 액션값들을 사용합니다.
그렇게 하기위해서는 액션도 export를 해야합니다.
import { productActions } from "../reducers/productReducer";
function getProducts(searchQuery) {
return async (dispatch, getState) => {
let url = ``'
let response = await fetch(url);
let data = await response.json();
dispatch(productActions.getAllProducts({ data }));
};
}
매개변수로 전달된 값은 이름을 굳이 payload라고 쓰지않아도 알아서 payload라는 필드 아래로 들어가게됩니다.
예시) action.payload.data
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
export const apiSlice = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:3500' }),
tagTypes: ['Todos'],
endpoints: (builder) => ({
getTodos: builder.query({
query: () => '/todos',
transformResponse: res => res.sort((a, b) => b.id - a.id),
providesTags: ['Todos']
}),
addTodo: builder.mutation({
query: (todo) => ({
url: '/todos',
method: 'POST',
body: todo
}),
invalidatesTags: ['Todos']
}),
updateTodo: builder.mutation({
query: (todo) => ({
url: `/todos/${todo.id}`,
method: 'PATCH',
body: todo
}),
invalidatesTags: ['Todos']
}),
deleteTodo: builder.mutation({
query: ({ id }) => ({
url: `/todos/${id}`,
method: 'DELETE',
body: id
}),
invalidatesTags: ['Todos']
}),
})
})
export const {
useGetTodosQuery,
useAddTodoMutation,
useUpdateTodoMutation,
useDeleteTodoMutation
} = apiSlice
서버에 대해 수행하려는 작업 집합입니다. 빌더 구문을 사용하여 객체로 정의합니다. 두 가지 기본 끝점 유형이 있습니다. query및 mutation.
문자열 태그 유형 이름의 배열입니다. 태그 유형 지정은 선택 사항이지만 캐싱 및 무효화에 사용할 수 있도록 정의해야 합니다. 태그 유형을 정의할 때 엔드포인트 를 구성할 때 태그 유형 을 제공 하고 무효화 할 수 있습니다 .providesTags, invalidatesTags
reducerPath서비스 가 스토어에 탑재될 고유 키 입니다. 애플리케이션에서 두 번 이상 호출하는 경우 createApi매번 고유한 값을 제공해야 합니다. 기본값은 'api'입니다.
(optional, only for query endpoints)
Used by query endpoints. Determines which 'tag' is attached to the cached data returned by the query. Expects an array of tag type strings, an array of objects of tag types with ids, or a function that returns such an array.
(optional, only for mutation endpoints)
Used by mutation endpoints. Determines which cached data should be either re-fetched or removed from the cache. Expects the same shapes as providesTags.