본문 바로가기

리덕스

Async Actions with Redux Thunk

리덕스는 아래와 같은 흐름으로 동작합니다.

 

리덕스 미들웨어가 있을때 동작하는 흐름은 아래와 같습니다.

리덕스는 동기적인 흐름을 통해 동작합니다. 액션 객체가 생성되고, 디스패치가 액션 발생을 스토어에게 알리면,

리듀서는 정해진 로직에 의해 액션을 처리한 후 새로운 상태값을 반환하는 과정입니다.

그러나 동기적인 흐름만으로 처리하기 어려운 예로

-외부 데이터 요청하여 그에 따른 응답을 화면에 보여주어야 할 때 

-시간을 딜레이시켜 동작하게 할 때

이러한 경우를 위해 비동기 작업을 처리하리하는 데 있어 미들웨어를 주로 사용합니다.

 

외부 데이터를 요청하여 화면에 보여주기위해 다음과 같이 구조를 만들었습니다.

blog
-src
-- actions
--- index.js
-- apis
--- jsonPlaceholder.js
-- components
--- App.js
--- PostList.js
-- reducers
--- index.js
--- postsReducer.js
-- index.js

index.js에서 리듀서와 미들웨어를 스토어에 연결해줍니다.

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

import App from './components/App';
import reducers from './reducers';

const store = createStore(reducers, applyMiddleware(thunk));

ReactDOM.render(
  <Provider store={store}>
    <App/>    
  </Provider>,
  document.querySelector('#root')   
);

apis 디렉토리에 jsonPlaceholder.js를 만들어줍니다.

import axios from 'axios';

export default axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com'
});

actions 디렉토리에 index.js를 만들어줍니다.

import jsonplaceholder from '../apis/jsonPlaceholder';

export const fetchPosts = () => async dispatch => {
  const response = await jsonplaceholder.get('/posts')
  
  dispatch({ type:'FETCH_POSTS', payload: response.data })
};

components 디렉토리에 PostList.js를 만들어줍니다.

import React from 'react';
import { connect } from 'react-redux';
import { fetchPosts } from '../actions';

class PostList extends React.Component {
  componentDidMount() {
    this.props.fetchPostsAndUsers();
  }  
  
  renderList() {
    return this.props.posts.map(post => {
      return (
        <div className="item" key={post.id}>
          <i className="large middle aligned icon user"/>
          <div className="content">
            <div className="description">
              <h2>{post.title}</h2>
              <p>{post.body}</p>
            </div>
          </div>
        </div>
      );
    });
  }

  render() {
    return <div className="ui relaxed divided list">{this.renderList()}</div>
  }
}

const mapStateToProps = (state) => {
  return { posts: state.posts };
}

export default connect(mapStateToProps, { fetchPosts })(PostList);

reducers 디렉토리에 index.js는 combineReducers 역할을 합니다.

postsReducer.js는 아래와 같이 만들어줍니다.

export default (state = [], action) => {
  switch (action.type) {
    case 'FETCH_POSTS':
      return action.payload;
    default:
      return state;
  }
};
참고! 리듀서의 규칙
1. 무조건 어떤 값을 리턴해야한다. string, null, object 등 값을 리턴해야한다. 'undefined'는 안된다.
2. state를 직접적으로 변경하면 안된다.

정상 작동된다면 아래와 같이 호출된 결과물을 확인 할 수 있다.

'리덕스' 카테고리의 다른 글

How to Use Redux with React Hooks  (0) 2021.05.06