Vishal Shetty
Vishal Shetty

Reputation: 1668

How to dispatch a action in React js after one action is completed?

In my React JS project.

I am listing the restaurant list to the customers. There are filters mainly the cuisine filter. Customers can select the cuisine and then data will be fetched from the API and re-rendered.

Redux Store to store the data

{
    restaurants: [],
    filters: {
        cuisines: []
    }
}

restaurants: [] will store all the restaurant's data, while cuisines: [] stores the filtered cuisine ids.

In componentWillMount() I have the logic which fetches the restaurants from the API and stores it inside the redux store.

At the same time, it will also check for the cuisines: [] from store to get the filtered data from the API.

Here is my filters component.

import React from 'react';
import {connect} from 'react-redux';

import {setSelectedCuisine, removeSelectedCuisine} from './../../actions/filterActions';
import {setRestaurants} from './../../actions/restaurantActions';

import {fetchRestaurants} from './../../utils/ApiLibrary';

import {loadJsLibraries} from './../../utils/LoadLibrary';

class Filters extends React.Component {

    lat = this.props.location.latitude;
    lng = this.props.location.longitude;
    maxDistance = 50;
    category = 'nearby';
    limit = 50;
    cuisineIds = this.props.filters.cuisines || [];
    restaurantAPI = '/gokhana/restaurant/categorized';

    cuisineStatus = (id) => {
        const cuisineFound = this.props.filters.cuisines.find((cuisineId) => {
            return cuisineId === id;
        });
        return cuisineFound ? true: false;
    }

    handleCheckBoxChange = (e) => {
        let isChecked = e.target.checked;
        isChecked ? 
            this.props.setSelectedCuisine(e.target.value) 
            : this.props.removeSelectedCuisine(e.target.value);

            fetchRestaurants(
                this.restaurantAPI,
                this.lat,
                this.lng,
                this.maxDistance,
                this.category,
                this.limit,
                this.cuisineIds
            ).then(result => dispatch(this.props.setRestaurants(result)));
    }

    render() {
        return (
            <div className="col-md-3">
                <div id="filters_col">
                    <a 
                        data-toggle="collapse" 
                        href="#collapseFilters" 
                        aria-expanded="true" 
                        aria-controls="collapseFilters" 
                        id="filters_col_bt
                    "> 
                    Filters 
                        <i className="icon-plus-1 pull-right"></i>
                    </a>

                    <div className="collapse" id="collapseFilters">

                        <div className="filter_type">
                            <h6>Distance</h6>
                            <input type="text" id="range" value="" name="range"/>
                            <input type="text" id="range-test" value="" />

                            <h6>Food Type</h6>
                            <ul>
                                <li><label><input type="checkbox" className="icheck" />Veg Only</label></li>
                            </ul>
                            <h6>Outlet Type</h6>
                            <ul>
                                <li><label><input type="checkbox" className="icheck" />Restaurant</label></li>
                                <li><label><input type="checkbox" className="icheck" />Food Court</label></li>
                            </ul>
                        </div>

                        <div className="filter_type">
                            <h6>Cuisines</h6>
                            <ul className="nomargin">
                                {
                                    this.props.cuisines.map((cuisine) => {
                                        return (<li>
                                            <label className="checkbox-container">
                                                {cuisine.name}

                                                <input 
                                                    type="checkbox"
                                                    value={cuisine.id} 
                                                    className="cuisineCheckbox"
                                                    onChange={(e) => this.handleCheckBoxChange(e)}
                                                    {...this.cuisineStatus(cuisine.id) ? {checked: true} : {} }
                                                />
                                                <span className="checkmark"></span>
                                            </label>
                                        </li>)
                                    })
                                }
                                {loadJsLibraries()}

                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

const mapStateToProps = {
    setSelectedCuisine,
    removeSelectedCuisine,
    setRestaurants
};

export default connect(state => state, mapStateToProps)(Filters);

I have multiple cuisines checkboxes, Now, when I check a checkbox then setSelectedCuisines action is dispatched, and if I uncheck a checkbox removeSelectedCuisine is dispatched.

This mechanism is working perfect, no problem. Now, the actual problem is.

Whenever, setSelectedCuisines or removeSelectedCuisines gets called, after completion of this action, I want to call the API which fetches the restaurant data based upon the filters selected.

After calling API, I also want to dispatch the action setRestaurants which will set the restaurants in store.

In above component, you can see the handleCheckBoxChange dispatching the setSelectedCuisines and removeSelectedCuisines. And at the same time I am calling a function to fetch the restaurants from the API and dispatch the setRestaurant.

Problem here is that, the setRestaurants action gets called immediately after cuisines action gets called and I am not getting the correctly filtered data from the API.

I am worried about this, as I am not sure where and when can I call the fetchRestaurants() function so that I get filtered data.

Upvotes: 0

Views: 163

Answers (2)

Rohith Murali
Rohith Murali

Reputation: 5669

I will tell you two ways to do this,

  1. Add the logic for creating the array of selected cuisines in the handleChange() to a variable and use this value to Call the api and send the dispatch.

  2. Use pub-sub and inside your reducer, after merging with the existing cuisines in case of checkbox selection or removing old ones otherwise, and then call the pubsub PubSub.publish() to call a function which fetches your api.

Upvotes: 1

Prabhu
Prabhu

Reputation: 1057

You can dispatch the function like below

this.props.dispatch(this.props.setRestaurants(result))

Upvotes: 0

Related Questions