👨🎓 Redux-thunk를 이해하기 위해 이래저래 문서를 찾다가 벨로퍼트님의 모던 리액트를 보며 공부했다, 그중 Promise를 이용한 Redux-thunk를 보는데 처음 보는 입장에서 이게 무슨말인지를 몇시간동안 되새기다가 풀이를 써볼려고 글을 쓴다.
👩💻 우선 뭘 할꺼냐면 더미데이터 API를 만들어서 요청&겟 한 다음 VIEW에 뿌려줄거다.
1. 더미데이터 API준비
// 데미데이터 목록
const posts = [
{
id: 1,
title: '리덕스 미들웨어를 배워봅시다',
body: '리덕스 미들웨어를 직접 만들어보면 이해하기 쉽죠.'
},
{
id: 2,
title: 'redux-thunk를 사용해봅시다',
body: 'redux-thunk를 사용해서 비동기 작업을 처리해봅시다!'
},
{
id: 3,
title: 'redux-saga도 사용해봅시다',
body:'나중엔 redux-saga를 사용해서 비동기 작업을 처리하는 방법도 배워볼 거예요.'
}
];
1-1 더미데이터를 조회 할 함수들
const sleep = n => new Promise(resolve => setTimeout(resolve, n));
// n 시간동안 딜레이를 주는 프로미스를 만들어주는 함수 (0.5초)
// 0.5초 딜레이를 줘서 실행이 겹치는 걸 막는 것 같다.
// 포스트 목록 전체를 가져오는 비동기 함수
export const getPosts = async () => {
await sleep(500); // 0.5초 쉬고
return posts; // posts 배열
};
// ID로 포스트를 조회하는 비동기 함수
export const getPostById = async id => {
await sleep(500); // 0.5초 쉬고
return posts.find(post => post.id === id); // id 로 찾아서 반환
};
2. 리덕스로 더미데이터를 조회 할 수 있는 모듈을 만든다.
👨🎓 리덕스 쓸 때 필요한 것들
import * as postsAPI from '../api/posts';
// api/posts 안의 함수 모두 불러오기
/* initialState 설정 */
const initialState = {
posts: {
loading: false,
data: null,
error: null
},
post: {
loading: false,
data: null,
error: null
}
};
/* 액션 타입 */
// 포스트 여러개 조회하는 액션타입들
const GET_POSTS = 'GET_POSTS'; // 요청 시작
const GET_POSTS_SUCCESS = 'GET_POSTS_SUCCESS'; // 요청 성공
const GET_POSTS_ERROR = 'GET_POSTS_ERROR'; // 요청 실패
// 포스트 하나 조회하는 액션타입들
const GET_POST = 'GET_POST';
const GET_POST_SUCCESS = 'GET_POST_SUCCESS';
const GET_POST_ERROR = 'GET_POST_ERROR';
/* 액션 생성함수 작성 */
export const getAllPostRequest = () => async dispatch => {
dispatch({ type: GET_POSTS }); // 요청이 시작됨
//async를 쓰는 이유는 요청을 시작하고 postsAPI.getPosts()를 실행해야하기 때문
try {
const posts = await postsAPI.getPosts(); // API 호출
dispatch({ type: GET_POSTS_SUCCESS, posts }); // 성공
} catch (e) {
dispatch({ type: GET_POSTS_ERROR, error: e }); // 실패
}
};
export const findPostRequest = id => async dispatch => {
dispatch({ type: GET_POST }); // 요청이 시작됨
try {
const post = await postsAPI.getPostById(id); // API 호출
dispatch({ type: GET_POST_SUCCESS, post }); // 성공
} catch (e) {
dispatch({ type: GET_POST_ERROR, error: e }); // 실패
}
};
/* 액션 생성함수 작성 end */
/* 리듀서 작성 */
export default function posts(state = initialState, action) {
switch (action.type) {
case GET_POSTS:
return {
...state,
posts: {
loading: true,
data: null,
error: null
}
};
case GET_POSTS_SUCCESS:
return {
...state,
posts: {
loading: true,
data: action.posts,
error: null
}
};
case GET_POSTS_ERROR:
return {
...state,
posts: {
loading: true,
data: null,
error: action.error
}
};
case GET_POST:
return {
...state,
post: {
loading: true,
data: null,
error: null
}
};
case GET_POST_SUCCESS:
return {
...state,
post: {
loading: true,
data: action.post,
error: null
}
};
case GET_POST_ERROR:
return {
...state,
post: {
loading: true,
data: null,
error: action.error
}
};
default:
return state;
}
}
CreateStore에 넣기
const store = createStore(reducer명)
화면에 뿌리기
const propsData = useSelector((state) => state.posts.데이터명); // 조회 한 후 map처리
📋 결과물