Search code examples
javascriptreactjsreduxaxiosredux-thunk

Returning promise object on GET API request by Redux and Axios


I am trying to fetch data by sending get request to api, I am getting data but Its in the promise object,

I have tried in couple of techniques to resolve this issue, but I am unable to solve the problem.

Reducer: personal-detail-reducer.js

import Http from "../utils/Http";
import {PERSONAL_DETAIL} from "../constants/api";
import {GET_PERSONAL_DETAIL} from "../constants/personsal-detail-constants";

const initialState = {
    data: ''
};

const personalDetailReducer = (state = initialState, action) => {
    if(action.type === GET_PERSONAL_DETAIL){
        return (dispatch) => {
            return Http.get(PERSONAL_DETAIL).then(response => {
                return{
                    data: dispatch(response.data.data)
                };
            }).catch(error => {});
        }
    }
    return state;
};

export default personalDetailReducer;

Component: personal-detail.js

const mapStateToProps = (state) => {
    return{
        state
    }
};
const mapDispatchToProps = (dispatch) => {
    return {
        onGetPersonalDetail: () => dispatch({type: GET_PERSONAL_DETAIL})
    }
}
export default connect(mapStateToProps, mapDispatchToProps) (TutorPersonalDetail);

I have already configured thunk

store.js

import {createStore, applyMiddleware} from 'redux';
import thunkMiddleware from 'redux-thunk';
import {createLogger} from 'redux-logger';
import {rootReducer} from '../reducers/index';

const loggerMiddleware = createLogger();

export const store = createStore(
    rootReducer,
    applyMiddleware(
        thunkMiddleware,
        loggerMiddleware
    )
);

Please find the attachment for reference Here is the dispatch response in next state and console as well which is returning dispatch


Solution

  • I usually don't include the HTTP calls in my reducers. Remember the reducers are all sync calls, so a good way to handle this is inside a thunk action. Here is an example:

    /** Notice that those actions are private. not exported to the components */
    const getPersonalDetailStart = () => {
      return {
        type: GET_PERSONAL_DETAIL_START
      };
    };
    
    const getPersonalDetailSuccess = (profile) => {
      return {
        type: GET_PERSONAL_DETAIL_SUCCESS,
          profile
      }
    };
    
    const getPersonalDetailFailure = (error) => {
      return {
        type: GET_PERSONAL_DETAIL_FAILURE,
          error
      };
    };
      
      /** Here is the thunk action that is available to components */
    export const getPersonalDetail = () => (dispatch) => {
        // Fire start action to display a loading indicator for example
      dispatch(getPersonalDetailStart());
        // Return the promise the thunk middleware
      return BackendAPI.getPersonalDetail().then(
          // on success, fire successful action.
        response => dispatch(getPersonalDetailSuccess(response.data.profile)),
          // on failure, fire failure action to e.g. show error message to user
        error => dispatch(getPersonalDetailFailure(error))
      );
    };
    

    Now on your reducer, just handle the actions in the same way a sync action will occur.

    export const personalReducer = (state, action) => {
    
      switch (action.type) {
      case GET_PERSONAL_DETAIL_START:
        return {
          ...state,
          isLoading: true
        };
      case GET_PERSONAL_DETAIL_SUCCESS:
        return {
          ...state,
          isLoading: false,
          profile: action.profile
        };
      case GET_PERSONAL_DETAIL_FAILURE:
        return {
          ...state,
          isLoading: false,
          error: error
        };
      default:
        return state;
      }
    
    }; 
    

    A demonstration in component could be as follows:

    import React, {Component, Fragment} from 'react';
    import {bindActionCreators} from "redux";
    import {connect} from 'react-redux';
    import {getPersonalDetail} from './actions/your_actions';
    
    export default class DemoComponent extends Component {
    
      componentDidMount() {
        const {getPersonalDetail} = this.props;
        getPersonalDetail();
      }
    
      render() {
        return <div>your html here</div>;
      }
    
    }
    
    
    const mapDispatchToProps = (dispatch) => {
      return bindActionCreators({getPersonalDetail}, dispatch);
    };
    
    
    DemoComponent = connect(null, mapDispatchToProps)(DemoComponent);