Easiest Way to Learn Redux Thunk with Example

What is redux-thunk?

We have already created a blog for Redux in React JS, now we will implement a redux-thunk middleware in this project. For those who have no basic react-redux knowledge, I recommend reading that blog first. Why we need this redux thunk with example blog? If we search redux-thunk all blog explains it as middleware. But not getting a clear idea on how it will work in the easiest method. So I thought to explain Redux thunk with an example.

Redux-thunk is not alternate of Redux, but it extends Redux functionality and works as middleware by which we can keep our reducer code clean from API calls and once we get API response we can easily dispatch our event. Redux-thunk comes in picture when we have API calls or some async task we are doing. If you want to understand redux first please read my previous blog.

Basically, it just provides a way to perform side effects.

Below is what we will achieve at the end of our blog.

easiest-demo-redux-thunk-reactjs

So let’s dive into code directly

install redux-thunk in project using below command

npm install -save redux-thunk

Add thunk as middleware in store

After setup package we have to import redux-thunk and add thunk as middleware in createStore.

import { combineReducers, createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

const initialState = {
    activeTab: 1,
    movieList: [],
    movieDetailList: []
}

export const actionReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'tabClicked':
            return {
                ...state,
                activeTab: action.activeTab
            }
        case 'SET_MOVIE_LIST':
            return {
                ...state,
                movieList: action.payload
            }
        }
        default:
            return state;
    }
};

export const reducers = combineReducers({ actionReducer });

// store.js
export const store = createStore(reducers, applyMiddleware(thunk));

Now we just need to use redux as it is, rest will be automatically handled by thunk dispatch. Let’s see how we can implement API and dispatch our action from API success. For our demo, we will add our API call in action.js as below.

export const tabClicked = (activeTab) => ({
    type: 'tabClicked',
    activeTab: activeTab
});

export const getMovieList = () => async (dispatch) => {
    try {
        const { data } = await 
            axios.get('https://api.themoviedb.org/3/list/1?api_key=xxx&language=en-US');
        dispatch(setMovieList(data));
    } catch (err) {
        console.log('error', err);
    }
};


export const setMovieList = (movie_lists) => {
    return {
        type: 'SET_MOVIE_LIST',
        payload: movie_lists
    };
};

So in the above code, you can see we are dispatching SET_MOVIE_LIST Please check again reducer.js above for checking the implementation of SET_MOVIE_LIST method.

Method setMovieList provides JSON payload which we are dispatching for our reducer. And the rest is all same as redux.

Now let’s see how we can call getMovieList API from component MovieList.jsx.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getMovieList } from '../../actions/';
import MovieDetail from '../movie-detail/MovieDetail.jsx'

class MovieList extends Component {

    constructor(props) {
        super(props);
        this.state = {
            sawMovieDetail: false,
            selectedMovieId: 0
        }
    }

    componentWillMount() {
        this.props.getMovieList();
    }

    clicked = (param_movie_id) => {
        this.setState({
            selectedMovieId: param_movie_id,
            sawMovieDetail: true
        });
    }

    hideMovieDetail = () => {
        this.setState({ sawMovieDetail: false });
    }

    render() {

        return (
            <div className="container">
                {(this.state.sawMovieDetail) ?

                    <MovieDetail
                        sharedMovieId={this.state.selectedMovieId}
                        onHideMovieDetail={this.hideMovieDetail} /> :

                    <div className="container-fluid">
                        <div className="card-columns">

                            {typeof this.props.movieList.items !== 'undefined' &&
                                this.props.movieList.items.map((option, index) =>

                                    <div className="card" key={index}>
                                          <a onClick={() => this.clicked(option.id)} style={{'cursor': 'pointer'}}>

                                            <img
                                                className="card-img-top"
                                                src={'https://image.tmdb.org/t/p/w185_and_h278_bestv2/' + option.poster_path}
                                                alt="not found" />

                                            <div className="card-body">
                                                <h5 className="card-title">{option.title}</h5>
                                                <p className="card-text">{option.description}</p>
                                            </div>

                                        </a>
                                    </div>

                                )}
                        </div>
                    </div>
                }
            </div>
        )
    }
}



function mapStateToProps(state) {
    return { movieList: state.actionReducer.movieList }
}

const mapDispatchToProps = { getMovieList };

const movieList = connect(
    mapStateToProps,
    mapDispatchToProps
)(MovieList);

export default movieList;

Mapping of mapStateToProps and mapDispatchToProps in MovieList prop is same as redux.

Let’s recap again why we need thunk with redux

So think again if we want to implement API without Redux, we have to mess up with our reducer.

Now we can call it as action and it’s not doing anything in reducer yet once its response will come, we are dispatching setMovieList reducer call which provides data to our view via Redux.

Don’t miss the next post!

Loading

Related Posts