비동기 사용 Redux-thunk

김수민·2023년 1월 30일
0

React

목록 보기
14/17

npm install redux thunk이 설치되어있어야한다.

const store= createStore(rootReducer,applyMiddleware(ReduxThunk, logger));

react에서 비동기를 사용할 수 있게 해주는 redux-thunk

redux-thunk의 구성

const thunk= store=> next=> action=> {
	typeof action=== 'function'?
    action(store.dispatch, store.getState):
    next(action)
}

값에 접근하는 방법


에서 posts의 data에 접근한다면,

	useSelector(state=>state.posts.posts.data);

작성법

1. data 및 함수 작성

[api/posts.js]
const sleep= n=> new Promise(resolve=>setTimeout(resolve,n));
const posts= [
	{id:1, title:"study redux", desc:"go"}, 
	{id:2, title:"study redux middleware", desc:"go!"}, 
	{id:3, title:"study redux-thunk", desc:"go!!"}, 
]

// post 목록을 return하는 비동기 함수
export const getPosts= async ()=>{
	await sleep(500);
	return posts;
}

// ID로 post를 리턴하는 비동기 함수
export const getPostById= async (id)=>{
	await sleep(500);
	return posts.find(post=> post.id===id); // id 일치하는 항목 찾아서 반환
}

2. 💡 thunk 작성

[modules/posts.js]
// *로 받으면 함수들이 들어있는 객체로 받음
// as는 받아온 데이터에 이름을 지정해주는것
// postsAPI= {getPosts,getPostByID}
import * as postsAPI from '../api/posts';

// ---액션타입---
const GET_POSTS= "GET_POSTS";
const GET_POSTS_SUCCESS = "GET_POSTS_SUCCESS";
const GET_POSTS_ERROR= "GET_POSTS_ERROR";

// ---💡 thunk 함수---
export const getPosts = ()=> async (dispatch)=>{
	dispatch({type: GET_POSTS}) // 요청이 시작됨
	try{
		const post= await postsAPI.getPosts();
		dispatch({type:GET_POSTS_SUCCESS, data:post})
	}
	catch(e){
		dispatch({type:GET_POSTS_ERROR, error:e})
	}
}

또는...

서버의 data 불러오기

npm install axios가 설치되어있어야한다.

//상 동

// ---💡 thunk 함수---
export const getPosts = ()=>async(dispatch)=>{
	dispatch({type: GET_POSTS}) // 요청이 시작됨
	try{
		const post= await axios.get('http://localhost:3005/posts');
		dispatch({type:GET_POSTS_SUCCESS, data:post.data})
	}
	catch(e){
		dispatch({type:GET_POSTS_ERROR, error:e})
	}
}

이하 동일

// ---상태 초기값---
const initialState={
	posts:{loading: false, data:null, error: null},
}

// ---reducer---
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: false, data: action.data, error:null}
				// action.data의 data는 getPosts의 dispatch에서 받아오는 값의 key이다.
			};
		case GET_POSTS_ERROR:
			return{
				...state,
				posts:{loading: false, data: null, error:action.error}
				// action.error의 error는 getPosts의 dispatch에서 받아오는 값의 key이다.
			};

		default:
			return state;
	}
}

3. redux combineReducers

[modules/index.js]
import { combineReducers } from "redux";
import counter from "./counter";
import posts from "./posts";

const rootReducer= combineReducers({counter, posts});
export default rootReducer;

4. 로딩이 완료 되었을 때 출력할 구문 작성

[components/PostList.js]
import React from 'react';

const PostList = ({posts}) => {
	return (
		<ul>
			{posts.map(post=><li key={post.id}>
				{post.title}
			</li>)}
		</ul>
	);
};

export default PostList;

5. 로딩상태에 따라 출력될 구문 작성

[containers/PostListContainers.js]
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import PostList from '../components/PostList';
import { getPosts } from '../modules/posts';

const PostListContainers = () => {
	const {data,loading,error}= useSelector(state=>state.posts.posts)
	const dispatch= useDispatch();
	// 컴포넌트 마운트 후 post 목록을 요청
	useEffect(()=>{
		dispatch(getPosts())
	},[dispatch]);
	if(loading) return <div>로딩중</div>
	if(error) return <div>에러 발생</div>
	if(!data) return null;
	return (
		<PostList posts={data}/>
	);
};

export default PostListContainers;

6. 연결

[/index.js]import { applyMiddleware, createStore } from 'redux';import ReduxThunk from 'redux-thunk';const store = createStore(textReducer,applyMiddleware(ReduxThunk));
 const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);
[/App.js]
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import PostListContainers from './containers/PostListContainers';

function App() {
  return (
    <BrowserRouter>
      <div className="App">
        <Routes>
          <Route path='/' element={<PostListContainers/>}/>
        </Routes>
      </div>
    </BrowserRouter>
  );
}

export default App;

profile
sumin0gig

0개의 댓글