# A little history about async calls in Redux Speaking about asynchronously in JavaScript can be a little bit hard for beginners. Anyway, if you reading this post, probably I can expect that you have some experience with React and Redux and also you partly know how Redux works. If not, first please take a look at [documentation](https://redux.js.org/introduction/getting-started). I always believed that the best way to learn is to practice on live examples, so let's imagine that in your application exists a beautiful button for fetching some data. The problem is how can I show status, based on request state. So, first, we need to have three different action types. In our case (and probably in each other request) we will have **REQUEST**, **SUCCESS** and **FAILED** status. Let's define it in **types.js** file or whether you store types. ```javascript= export const FETCH_POSTS_REQUEST = 'fetch_posts_request'; export const FETCH_POSTS_SUCCESS = 'fetch_posts_success'; export const FETCH_POSTS_FAILURE = 'fetch_posts_failure'; ``` If you don't want to implement this in your app I prepared example here: https://github.com/KPowroznik/redux-async-post/tree/entry As you can see, I prepared a button which should react to state changes. Let's implement our async calls in a basic way. First, let's write some action creator. We need to remember that action creators should be synchronously and they don't have access to the redux store. So, our **actions.js** file with action creators should looks like this: ```javascript= import { FETCH_POSTS_REQUEST, FETCH_POSTS_SUCCESS, FETCH_POSTS_FAILURE } from './types'; export const fetchPosts = () => ({ type: FETCH_POSTS_REQUEST }); export const fetchPostsSuccess = (posts) => ({ type: FETCH_POSTS_SUCCESS, payload: posts }); export const fetchPostsFailure = (reason) => ({ type: FETCH_POSTS_FAILURE, payload: reason }); ``` Also, we need to create our reducer: ```javascript= switch (action.type) { case FETCH_POSTS_REQUEST: return { ...state, isLoading: true, loadingState: 'loading', error: '' }; case FETCH_POSTS_SUCCESS: return { ...state, isLoading: false, loadingState: 'success', posts: action.payload }; case FETCH_POSTS_FAILURE: return { ...state, isLoading: false, loadingState: 'failure', error: action.payload }; default: return state; } ``` After one we need to bind our action creators in mapDispatchToProps: ```javascript= const mapDispatchToProps = (dispatch) => ({ fetchPostsActions: bindActionCreators(actions, dispatch) }); ``` Then we can use it in that way: ```javascript= const handleFetch = () => { fetchPosts(); fetch('https://jsonplaceholder.typicode.com/posts') .then((response) => response.json()) .then((data) => fetchPostsSuccess(data)) .catch((error) => fetchPostsFailure(error.message)); }; ``` So what we do here? First, I've created some action creators, next I bind all of that action object to dispatch. Why I use bindActionCreators you can find here: https://redux.js.org/api/bindactioncreators. The last thing was to create handleSubmit function where I perform my actions depends on the fetch state. And this approach is correct, but... but it looks strange and it's hard to maintain. Let us imagine what if you'll want to use the same fetch data steps in other places in your app? Probably you need to duplicate your code and also we wire our UI with business logic. That's not [KISS](https://en.wikipedia.org/wiki/KISS_principle). How can we play with that? Let's invite middleware. ## middlewares "With a plain basic Redux store, you can only do simple synchronous updates by dispatching an action. Middleware extend the store's abilities, and let you write async logic that interacts with the store." ~ *redux-thunk documentation* **redux-thunk** it's that's one which helps us to create action creators with side effects (with it our action creators can return function - not object). So, let us rewrite our app to this approach. The first one will install the required dependency and configure it in our store. ```javascript= import { createStore, compose, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import { rootReducer } from './rootReducer'; const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; export const store = createStore( rootReducer, composeEnhancers(applyMiddleware(thunk)) ); ``` The only thing that I do here is import applyMiddleware from redux and also import redux-thunk library. Then I can combine these two things. That's all. As you can see we don't need to configure anything. All of "thunk" magic working under the hood. What is a thunk? A thunk is a function that wraps an expression to delay its evaluation. So, with thunk, we can delay our dispatch. With that, we can do some changes in our actions. ```javascript= export const fetchPostsRequest = () => ({ type: FETCH_POSTS_REQUEST }); export const fetchPostsSuccess = (posts) => ({ type: FETCH_POSTS_SUCCESS, payload: posts }); export const fetchPostsFailure = (reason) => ({ type: FETCH_POSTS_FAILURE, payload: reason }); export const fetchPosts = () => (dispatch) => { dispatch(fetchPostsRequest()); fetch('https://jsonplaceholder.typicode.com/posts') .then((response) => response.json()) .then((data) => dispatch(fetchPostsSuccess(data))) .catch((error) => dispatch(fetchPostsFailure(error.message))); }; ``` Then we need to do some changes in App.js - import only fetchPosts action, change mapDispatchToProps to a plain object and delete handleSubmit function (we just use fetchPosts props instead of this). ```javascript= const App = ({ isLoading, loadingState, fetchPosts }) => { return ( <div className='app'> <LoadingButton isLoading={isLoading} loadingState={loadingState} handleFetch={fetchPosts} /> </div> ); }; const mapStateToProps = (state) => ({ isLoading: state.isLoading, loadingState: state.loadingState }); const mapDispatchToProps = { fetchPosts }; ``` As you see, we've composed a function that do all things in one place. That looks cool. Now we can be sure that this code will be reusable and also easy to maintain. So what is the conclusion? redux-thunk is a middleware that helps us with async calls in our redux state. Without that, we can't pass actions which are functions. This is a very interesting concept because it gives us a possibility to compose actions, which uses other actions. There's any other options to play with async calls? Basically yes. This is the power of open-source software. For more complex solutions we can use the redux-saga library. Redux-saga is another middleware for redux. The main difference between thunks and sagas is separate logic from action creators to sagas, so our action creators still stay pure. How to play with that? First, we need to configure. There is a little bit more work than in thunk but it also easy and documentation for that is written clearly. ```javascript= import { createStore, compose, applyMiddleware } from 'redux'; import { rootReducer } from './rootReducer'; import { rootSaga } from './sagas'; import createSagaMiddleware from 'redux-saga'; const sagaMiddleware = createSagaMiddleware(); const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; export const store = createStore( rootReducer, composeEnhancers(applyMiddleware(sagaMiddleware)) ); sagaMiddleware.run(rootSaga); ``` Also, we need to create our sagas. redux-saga taking advantage of async generators and provides us some effects that we can use in our functions. ```javascript= import { call, put, takeEvery } from 'redux-saga/effects'; import { FETCH_POSTS_REQUEST } from './types'; import * as actions from './actions'; const apiService = () => fetch('https://jsonplaceholder.typicode.com/posts'); function* fetchPosts() { try { const res = yield call(apiService); const data = yield res.json(); yield put(actions.fetchPostsSuccess(data)); } catch (error) { yield put(actions.fetchPostsFailure(error.message)); } } export function* rootSaga() { yield takeEvery(FETCH_POSTS_REQUEST, fetchPosts); } ``` As you can see I created here generator function called fetchPosts and rootSaga. All of the operations in this functions taking advantage of Effects. An Effect is an object that contains some information to be interpreted by the middleware. To create Effects, we can use the functions provided by the library in the redux-saga/effects package. For example, takeEvery takes all of our action calls and takeLates get only last call. Of course, I showed you just basic examples of using sagas. There are too many concepts about sagas for one post, but sagas also have nice documentation: https://redux-saga.js.org/ In React world we have a lot of options that we can use in our project. I showed you three different ways to deal with async in redux. Choice is yours. Of course, probably you need to spend some time to get all of these things. With redux-thunk or redux-saga libraries, we can separate logic from our UI - this is a good practice because our code will be easy to maintain and easy to test, also you do async stuff.