// reateAsyncThunk 불러오기
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
let initialState = {
productList: [],
productDetailList: null,
isLoading: false,
error: null,
};
// 2개의 파라미터 action 타입(이름)의 string, 하고 싶은 일 콜백함수(promise 리턴)
export const fetchProducts = createAsyncThunk(
'product/fetchAll',
// 콜백함수는 2개의 매개변수 받음(arg, thunkAPI)
// arg: api 호출 전 넘겨야하는 single value
async (searchQuery, thunkApi) => {
try {
let url = `https://my-json-server.typicode.com/ryugotthis/shoppingmall-toolkit/products?q=${searchQuery}`;
let response = await fetch(url);
// promise 리턴
return await response.json();
} catch (error) {
// fetchProducts.rejected로 error 메시지 action.payload로 보냄
thunkApi.rejectWithValue(error.message);
}
}
);
const productSlice = createSlice({
name: 'product',
initialState,
reducers: {
// 리덕스에서 직접적 호출되는 경우
// getSingleProduct는 thunk(미들웨어)사용하는 action.js에 action이 별도로 정의되어서 dispatch로 넘겨줌
getSingleProduct(state, action) {
state.productDetailList = action.payload;
},
},
//외부 라이브러리에 의해서 호출이 되는 경우
extraReducers: (builder) => {
builder
.addCase(fetchProducts.pending, (state) => {
state.isLoading = true;
})
.addCase(fetchProducts.fulfilled, (state, action) => {
// 성공이 된 케이스니까 isLoading 먼저 false로 만들어줌
state.isLoading = false;
state.productList = action.payload;
})
.addCase(fetchProducts.rejected, (state, action) => {
state.isLoading = false;
//에러시 try catch문에서 받은 error.message를 action으로 받을수 있음
state.error = action.payload;
});
},
});
export const productActions = productSlice.actions;
// reducer에 모든 reducers 있음
export default productSlice.reducer;
action.js
import { productActions } from '../reducer/productReducer';
function getProductDetail(id) {
return async (dispatch, getState) => {
let url = ` https://my-json-server.typicode.com/ryugotthis/shoppingmall-toolkit/products/${id}`;
let response = await fetch(url);
let data = await response.json();
console.log('여기여기여기여기여기', data);
dispatch(productActions.getSingleProduct(data));
};
}
export const productAction = { getProductDetail };