I'm going to call api using redux
:
I used axios
,history
,react-redux
,react-router-native
,react-router
,,redux-promise-middleware
,redux-thunk
ponent to make api call using redux
:
I made Reducers
folder and put all my reducer file there in their own file and bine 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 bine them in the index.js file:
import { bineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
//import api from './api-reducer';
import generateotp from './generateotpReducer';
import login from './loginReducer';
export default bineReducers({
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 ponent file:
import { generateOTP } from "../Components/Actions/api";
and dispatch the action like this:
this.props.dispatch(generateOTP(formatted_phone_number));
I also connect the ponent 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 ponentWillReceiveProps
method to receive the result. I don't know why this ponent doesn't run. I searched too much I a find a confused result which said the state doesn't change then the ponentWillReceiveProps
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 ponentWillReceiveProps
(that doesn't run any more) which I used to receive the result of the api call.
I'm going to call api using redux
:
I used axios
,history
,react-redux
,react-router-native
,react-router
,,redux-promise-middleware
,redux-thunk
ponent to make api call using redux
:
I made Reducers
folder and put all my reducer file there in their own file and bine 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 bine them in the index.js file:
import { bineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
//import api from './api-reducer';
import generateotp from './generateotpReducer';
import login from './loginReducer';
export default bineReducers({
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 ponent file:
import { generateOTP } from "../Components/Actions/api";
and dispatch the action like this:
this.props.dispatch(generateOTP(formatted_phone_number));
I also connect the ponent 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 ponentWillReceiveProps
method to receive the result. I don't know why this ponent doesn't run. I searched too much I a find a confused result which said the state doesn't change then the ponentWillReceiveProps
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 ponentWillReceiveProps
(that doesn't run any more) which I used to receive the result of the api call.
-
Sorry if my question is dumb, which file would you actually deploy
ponentWillReceiveProps
, 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 Commented Apr 10, 2018 at 12:47 - 1 Have you used Provider, how are you creating the store and where exactly do you have ponentWillReceiveProps – Shubham Khatri Commented Apr 10, 2018 at 13:08
- @ShubhamKhatri thanks for reply, i shared my whole project in this path github./Husseinoj/reactapi – Hussein Ojaghi Commented Apr 10, 2018 at 15:14
- @Carr thanks, i shared the project in my github, the project worked well when i called only one api – Hussein Ojaghi Commented Apr 10, 2018 at 15:17
-
I checked out the project,
ponentWillReceiveProps
is getting called, but I cant resolve theapi
since it is pointing to your server maybe. – Pritish Vaidya Commented Apr 10, 2018 at 18:15
6 Answers
Reset to default 1Your 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; //!
...
}
ponentWillReceiveProps (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);
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 paring 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 pute 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.
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.
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 ments the reducer must be fixed.
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()