14

I'm going to call api using redux: I used axios,history,react-redux,react-router-native,react-router,,redux-promise-middleware,redux-thunk component to make api call using redux: I made Reducers folder and put all my reducer file there in their own file and combine them in a main file like this this is my generateoptReducer.js file:

const initialState = {
    data: {},
    error: null,
    status: null
};
import {generateOTP} from '../Actions/api';
export default function reducer(state = initialState, action) {

    switch (action.type) {
        case (action.type === 'GENERATEOTP_PENDING' || {}).input:
            // Action is pending (request is in progress)
            return {...state, status: 'fetching',methodes:'done1'};
        case (action.type === 'GENERATEOTP_FULFILLED' || {}).input:
            // Action is fulfilled (request is successful/promise resolved)
            return {
                ...state,
                error: null,
                data: action.payload.data,
                status: 'success',
                methodes:'done1'
            };
            case 'generateOTP':
                // Action is fulfilled (request is successful/promise resolved)
                return {
                    ...state,
                    error: null,
                    data: action.payload.data,
                    status: 'success',
                    methodes:'done1'
                };
        case (action.type === 'GENERATEOTP_REJECTED' || {}).input:
            // Action is rejected (request failed/promise rejected)
            return {
                ...state,
                error: action.payload,
                status: 'error'
            };
        default:
            return state;
    }
};

And combine them in the index.js file:

import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';

//import api from './api-reducer';


import generateotp from './generateotpReducer';
import login from './loginReducer';

export default combineReducers({
  generateotp,
  login,
  routing: routerReducer,
});

I also made another folder named Action and put all my api in a file named api.js:

This is my above reducer action:

export const generateOTP = (phone_number) => ({
    type: 'GENERATEOTP',
    payload: axios({
        method: 'GET',
        url: format(generate_endpoint, phone_number, serviceId),
        headers: {"Accept": "application/json","Content-Type":"application/json"}
    })
});

this is also my store:

import { applyMiddleware, createStore } from 'redux';
import { routerMiddleware } from 'react-router-redux';
import thunk from 'redux-thunk';
import promiseMiddleware from 'redux-promise-middleware';
import logger from 'redux-logger'
import reducers from './Reducers';

export default function configureStore(history) {
  const middleware = applyMiddleware(
    promiseMiddleware(),
    thunk,

    routerMiddleware(history));
  return createStore(reducers, {}, middleware);
}

and this is the way I dispatch the action: imported like this in above of my component file:

import { generateOTP } from "../Components/Actions/api";

and dispatch the action like this:

this.props.dispatch(generateOTP(formatted_phone_number));

I also connect the component like this in the bottom of the file:

export default connect(state => state)(SignIn)

Now I need the result of this api. I used to use the componentWillReceiveProps method to receive the result. I don't know why this component doesn't run. I searched too much I a find a confused result which said the state doesn't change then the componentWillReceiveProps doesn't run!!! the good thing is that the api call successfully and i can see the log and i can see the %cGENERATEOTP_PENDING and then %cGENERATEOTP_FULFILLED in the log and api call successfully but the problem is with the componentWillReceiveProps(that doesn't run any more) which I used to receive the result of the api call.

falinsky
  • 6,305
  • 3
  • 25
  • 50
Hussein Ojaghi
  • 2,060
  • 2
  • 18
  • 37
  • Sorry if my question is dumb, which file would you actually deploy `componentWillReceiveProps`, it's always good to provide enough information, but this one is hard to trace. Maybe you could reorganize it to help people who want to give a hand. – Carr Apr 10 '18 at 12:47
  • 1
    Have you used Provider, how are you creating the store and where exactly do you have componentWillReceiveProps – Shubham Khatri Apr 10 '18 at 13:08
  • @ShubhamKhatri thanks for reply, i shared my whole project in this path https://github.com/Husseinoj/reactapi – Hussein Ojaghi Apr 10 '18 at 15:14
  • @Carr thanks, i shared the project in my github, the project worked well when i called only one api – Hussein Ojaghi Apr 10 '18 at 15:17
  • I checked out the project, `componentWillReceiveProps` is getting called, but I cant resolve the `api` since it is pointing to your server maybe. – Pritish Vaidya Apr 10 '18 at 18:15
  • yes it's a local host server, okay i'll do it with another online api soon. it's a dommy ruby localhost app which only has two api, i tested the api with postman, it was good and in factit just a test, you know i have big problem with calling multi api in one component, – Hussein Ojaghi Apr 10 '18 at 18:41
  • `componentWillReceiveProps ` is getting called, what is the final solution that you want to receive? – Pritish Vaidya Apr 10 '18 at 22:48

6 Answers6

1

Your switch statement looks mailformed

case (action.type === 'GENERATEOTP_FULFILLED' || {}).input:

This will never run, because (action.type === 'GENERATEOTP_FULFILLED' || {}) will be either true, either {}, and ?.input will be always undefined

You need to write smth like this to validate some additional parameters:

switch (action.type) {
    case 'GENERATEOTP_PENDING':
        if (action.input) {
            // Action is pending (request is in progress)
            return {...state, status: 'fetching',methodes:'done1'};
        }
        break; //!
    ...
}
Andrii Muzalevskyi
  • 2,997
  • 13
  • 18
0
componentWillReceiveProps (nextProps){

console.log('get here',nextProps. fullState)

}

use connect like this

function mapStateToProps(state) {
console.log('get your state here',state)
  return {
   fullState: state.appState,
  };
}

export default connect(mapStateToProps, {generateOTP})(SignIn);
Sport
  • 6,972
  • 6
  • 38
  • 61
0

Your reducer code looks a bit off. You have:

switch (action.type) {
  case (action.type === 'GENERATEOTP_PENDING' || {}).input:
      // Action is pending (request is in progress)
      return {...state, status: 'fetching',methodes:'done1'};
  case (action.type === 'GENERATEOTP_FULFILLED' || {}).input:
      // Action is fulfilled (request is successful/promise resolved)
      return {
          ...state,
          error: null,
          data: action.payload.data,
          status: 'success',
          methodes:'done1'
      };
  case 'generateOTP':
      // Action is fulfilled (request is successful/promise resolved)
      return {
          ...state,
          error: null,
          data: action.payload.data,
          status: 'success',
          methodes:'done1'
      };
  // ... etc
}

The switch statement is looking at action.type, then the first two cases try to access (action.type === 'ACTION_NAME' || {}).input. This statement either resolves to (a Boolean instance).input, or {}.input. Each of these cases will be "falsey", because input is not a property on any of those values. When the code runs the program will be comparing action.type to (false || {}).input, which will never be true, and as such that case will not be run.

I am not sure what you are trying to compute in the first two cases there, but the next case in the switch statement looks more correct, where you just have an action name as a string (case 'generateOTP').

My assumption is that your reducer code never runs, even though the network request does.

grammar
  • 851
  • 9
  • 21
0

As the above answer mentioned your "reducer" file looks quite weird.

A switch case should be

switch (action.type) {
  case 'GENERATEOTP_PENDING':
    //stuff
    break;
  case 'GENERATEOTP_FULFILLED':
    //stuff
    break;
  case 'generateOTP':
    //stuff
    break;

but another issue I think we have is that the action of "generateOTP" is setting a "promise" inside the action to redux.

The reducer handles that like its a normal data object.

I would handle the promise of my action or at least make sure the reducers is handling that promise.

Tzook Bar Noy
  • 10,111
  • 12
  • 45
  • 75
  • he is using redux-promise-middleware which will take care of the promise in the payload. redux-proimise-middleware despatch actions accordingly when the promise is resolved. and the reducer should always be side effects free. so handling your peomise inside reducer is an anti-pattern in my opinion – Noushad Apr 17 '18 at 08:52
  • I don't handle it in the reducer :) I just said he should handle in the action but if he really wants he could do that in the reducer. I use redux saga and thunk – Tzook Bar Noy Apr 17 '18 at 09:37
0

Refactor your action as per below.

export function generateOTP() {
 return {
  type: 'GENERATE_OTP',
  payload:axios({
    method: 'get',
    url: 'http://10.0.2.2:3000/news',
    headers: {"Accept": "application/json"}
  }).then(success => {
    return success
  }).catch(fail => {
    return fail
 })
}

As per the above comments the reducer must be fixed.

Sachin
  • 266
  • 1
  • 2
  • 8
0

I suggest to dispatch an action not through this.props.dispatch but with just dispatch(generateOTP)

if you want this action to be avaliable in your props, then in connect method you have to fullfill mapDispatchToProps function.

In my code for example:

import * as postActions from '../actions/post'
import * as langActions from '../actions/lang'

const mapDispatchToProps = dispatch => {
  return bindActionCreators(Object.assign({},
     postActions,
     langActions,
  ), dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(News)

However, even if it's is your case then you access this action not through dispatch, but as any other fucntions from your props:

this.props.generateOTP()