Reputation: 107
i am new in react-redux and for the time been i have a simple page doing login to an existing service(the call is working and i am getting data from the server), i want to get the data in the component and set set cookie and redirect the user based in the data received from the server. I am getting the data in the action but in the component it is undefined. Thank you all
The submit function in the form component:
onSubmit(e) {
e.preventDefault();
if (this.isValid()) {
this.setState({ errors: {}, isLoading: true });
this.props.actions.loginUser(this.state).then(
function (res) {
this.context.router.push('/');
},
function (err) {
this.setState({ errors: err.response.data.errors, isLoading: false });
}
);
}
}
The action function :
import * as types from './actionTypes';
import loginApi from '../api/loginApi';
export function loginSuccess(result) {
return { type: types.LOGIN_SUCCESS, result };
}
export function loginFailed(result) {
return { type: types.LOGIN_FAILURE, result };
}
export function loginUser(data) {
return dispatch => {
return loginApi.loginUser(data).then(result => {
if (result) {
if (result.ErrorCode == 0)
dispatch(loginSuccess(result));
else
dispatch(loginFailed(result));
}
}).catch(error => {
throw (error);
});
};
}
The api:
static loginUser(data) {
return fetch(API + "/SystemLogin.aspx",
{
method: 'POST',
mode: 'cors',
body: JSON.stringify({
User: data.identifier,
Password: data.password
})
}).then(function (response) {
return response.json();
})
.then(function (parsedData) {
return parsedData;
//resolve(parsedData);
})
.catch(error => {
return error;
});
}
The reducer:
import * as types from '../actions/actionTypes';
import LoginApi from '../api/loginApi';
import initialState from './initialState';
export default function loginReducer(state = initialState.login, action) {
switch (action.type) {
case types.LOGIN_SUCCESS:
return [...state, Object.assign({}, action.courses)];
//return action.result;
case types.LOGIN_FAILURE:
return action.result;
default:
return state;
}
}
Is there any more code needed?
Upvotes: 1
Views: 2326
Reputation: 1602
First issue is with your reducer code. It should be like this:-
import * as types from '../actions/actionTypes';
import LoginApi from '../api/loginApi';
import initialState from './initialState';
export default function loginReducer(state = initialState.login, action) {
switch (action.type) {
case types.LOGIN_SUCCESS:
return Object.assign({}, state, { userProfile: action.results });
//return action.result;
case types.LOGIN_FAILURE:
return action.result;
default:
return state;
}
}
The second problem is with the way you are trying to send the user to another route. It should be like this:-
onSubmit(e) {
e.preventDefault();
if (this.isValid()) {
this.setState({ errors: {}, isLoading: true });
this.props.actions.loginUser(this.state);
}
}
The next problem is inside the render function.Inside render function, put a check for is your this.props.userProfile object is defined or not and if it is which will only happen on login success, then redirect him/her to the /homepage route using
this.context.router.push("/homepage");
Upvotes: 2
Reputation: 65
Could you check that did you connect the form component with redux ? If yes, you should access the action directly via this.props instead of this.props.actions.loginUser. Maybe this is not the problem because I haven't had a chance to look for the full code of your form component.
Hope this helps.
Upvotes: 0
Reputation: 10906
Although the code might be working, it is certainly a hassle to do all the above, the code is not easily comprehensible this way, since you are mixing "dirty" async code within the component and actions.
I advise you to use redux-saga
to separate the side-effects from the component and actions.
step 1: fire an action
step 2: catch the action inside a "saga" instead of a reducer:
import { put, takeEvery, all } from 'redux-saga/effects'
// Our worker Saga: will perform the async increment task
export function* loginUserAsync() {
yield put({ type: 'LOGIN_SUCCESS' })
}
// Our watcher Saga: spawn a new loginUserAsync task on each LOGIN_USER
export function* watchIncrementAsync() {
yield takeEvery('LOGIN_USER', loginUserAsync)
}
step 3: fire a new action after the async code is done and catch it inside a reducer to update state.
step 4: if you have more "dirty" code, simply run it inside the saga (redirection for example)
Upvotes: 1