在我的React / Redux应用程序中,当用户尝试登录时,我已经为用户创建了一个承诺。使用错误的凭据时,我的Reducer不会调用错误,但是,当我更改“登录”中的return语句时,将我的Auth.js文件上的函数转换为未定义的变量,例如' response'而不是'错误'它确实会调用错误并将其注册到我的Reducer上,我查看了其他帖子,但我无法弄明白。我有3个文件来处理这个逻辑,Auth,Sagas和Reducers。感谢任何帮助
Auth.js
import axios from 'axios';
import cookie from 'react-cookie';
export const API_URL = 'http://13.59.102.50:8000';
const transformRequest = (obj) => {
let str = [];
for (let p in obj) {
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
}
return str.join('&');
};
const auth = {
/**
* Logs a user in returning a promise with 'true' when done
*/
login(email, password) {
// if already logged in return promise
if (auth.loggedIn()) {
return Promise.resolve(true);
}
console.log('in login');
const data = {
email,
password,
};
const url = API_URL + '/tokens';
// post request
return axios.post(url, transformRequest(data))
.then(response => {
cookie.save('token', response.data.token, { path: '/' });
cookie.save('email', response.data.user.email, { path: '/' });
return response.data;
})
.catch((error) => {
console.log(error, 'This is an error')
});
},
/**
* Logs the user out
*/
logout() {
cookie.remove('token', { path: '/' });
cookie.remove('email', { path: '/' });
return Promise.resolve(true);
},
/**
*
* Checks if user is logged in
*/
loggedIn() {
return !!cookie.load('token');
},
/**
*
* Get user information
*/
getUserInfo() {
const email = cookie.load('email');
const token = cookie.load('token');
const url = API_URL + `/users/${email}`;
const config = {
headers: { 'Authorization': `Bearer ${token}` },
};
// post request
return axios.get(url, config)
.then(response => {
return { user: response.data };
})
.catch((error) => {
console.log(error.response);
});
return !!cookie.load('token');
},
/**
* Registers a user then logs them in
**/
register(name, email, password, account_type) {
const data = {
name,
email,
password,
account_type
};
const url = API_URL + '/users';
return axios.post(url, transformRequest(data))
.then(response => {
console.log('response:' + response);
return response.data;
})
.catch((error) => {
console.log(error.response);
});
},
};
export default auth;
Sagas.js
// This file contains the sagas used for async actions in our app. It's divided into
// "effects" that the sagas call (`authorize` and `logout`) and the actual sagas themselves,
// which listen for actions.
// Sagas help us gather all our side effects (network requests in this case) in one place
import { take, call, put, race } from 'redux-saga/effects';
import { browserHistory } from 'react-router';
import auth from 'utils/auth';
import { toastr } from 'lib/react-redux-toastr';
import {
SENDING_REQUEST,
LOGIN_REQUEST,
REGISTER_REQUEST,
SET_AUTH,
LOGOUT,
FETCH_USER,
CHANGE_FORM,
REQUEST_ERROR,
SET_USER,
CLEAR_USER,
} from './constants';
/**
* Effect to handle authorization
* @param {string} email The email of the user
* @param {string} password The password of the user
* @param {object} options Options
* @param {boolean} options.isRegistering Is this a register request?
*/
export function* authorize({ name, email, password, accountType, isRegistering }) {
// We send an action that tells Redux we're sending a request
yield put({ type: SENDING_REQUEST, sending: true });
// We then try to register or log in the user, depending on the request
try {
// let salt = genSalt(email);
// let hash = hashSync(password, salt);
let response;
// For either log in or registering, we call the proper function in the `auth`
// module, which is asynchronous. Because we're using generators, we can work
// as if it's synchronous because we pause execution until the call is done
// with `yield`!
if (isRegistering) {
response = yield call(auth.register, name, email, password, accountType);
} else {
response = yield call(auth.login, email, password);
}
return response;
console.log(response,'This is a big response')
} catch (error) {
console.log('hi');
// If we get an error we send Redux the appropiate action and return
yield put({ type: REQUEST_ERROR, error: error.message });
return false;
} finally {
// When done, we tell Redux we're not in the middle of a request any more
yield put({ type: SENDING_REQUEST, sending: false });
}
}
/**
* Effect to handle logging out
*/
export function* logout() {
// We tell Redux we're in the middle of a request
yield put({ type: SENDING_REQUEST, sending: true });
// Similar to above, we try to log out by calling the `logout` function in the
// `auth` module. If we get an error, we send an appropriate action. If we don't,
// we return the response.
try {
const response = yield call(auth.logout);
yield put({ type: SENDING_REQUEST, sending: false });
return response;
} catch (error) {
yield put({ type: REQUEST_ERROR, error: error.message });
return error.message;
}
}
/**
* Log in saga
*/
export function* loginFlow() {
// Because sagas are generators, doing `while (true)` doesn't block our program
// Basically here we say "this saga is always listening for actions"
while (true) {
// And we're listening for `LOGIN_REQUEST` actions and destructuring its payload
const request = yield take(LOGIN_REQUEST);
const { email, password } = request.data;
// A `LOGOUT` action may happen while the `authorize` effect is going on, which may
// lead to a race condition. This is unlikely, but just in case, we call `race` which
// returns the "winner", i.e. the one that finished first
const winner = yield race({
auth: call(authorize, { email, password, isRegistering: false }),
logout: take(LOGOUT),
});
// If `authorize` was the winner...
if (winner.auth) {
// ...we send Redux appropiate actions
yield put({ type: SET_AUTH, newAuthState: true }); // User is logged in (authorized)
yield put({ type: SET_USER, user: winner.auth });
yield put({ type: CHANGE_FORM, newFormState: { email: '', password: '' } }); // Clear form
yield call(forwardTo, '/'); // Go to dashboard page
// If `logout` won...
} else if (winner.logout) {
// ...we send Redux appropiate action
yield put({ type: SET_AUTH, newAuthState: false }); // User is not logged in (not authorized)
yield call(logout); // Call `logout` effect
yield call(forwardTo, '/login'); // Go to root page
}
}
}
/**
* Log out saga
* This is basically the same as the `if (winner.logout)` of above, just written
* as a saga that is always listening to `LOGOUT` actions
*/
export function* logoutFlow() {
while (true) {
yield take(LOGOUT);
yield put({ type: SET_AUTH, newAuthState: false });
yield call(logout);
yield put({ type: CLEAR_USER });
yield call(forwardTo, '/login');
toastr.success('Success!', 'You are now logged out.');
}
}
/**
* Get user information saga
*/
export function* getUserFlow() {
while (true) {
yield take(FETCH_USER);
try {
const response = yield call(auth.getUserInfo);
yield put({ type: SET_USER, user: response });
} catch (error) {
yield put({ type: REQUEST_ERROR, error: error.message });
return error.message;
}
}
}
/**
* Register saga
* Very similar to log in saga!
*/
export function* registerFlow() {
while (true) {
// We always listen to `REGISTER_REQUEST` actions
const request = yield take(REGISTER_REQUEST);
const { name, email, password, accountType } = request.data;
// We call the `authorize` task with the data, telling it that we are registering a user
// This returns `true` if the registering was successful, `false` if not
const wasSuccessful = yield call(authorize, {name, email, password, accountType, isRegistering: true });
// If we could register a user, we send the appropriate actions
if (wasSuccessful) {
yield put({ type: SET_AUTH, newAuthState: true }); // User is logged in (authorized) after being registered
yield put({ type: CHANGE_FORM, newFormState: { name: '', password: '' } }); // Clear form
yield put({ type: LOGIN_REQUEST, data: { email, password } });
forwardTo('/dashboard'); // Go to dashboard page
}
}
}
// The root saga is what we actually send to Redux's middleware. In here we fork
// each saga so that they are all "active" and listening.
// Sagas are fired once at the start of an app and can be thought of as processes running
// in the background, watching actions dispatched to the store.
export default [
loginFlow,
logoutFlow,
registerFlow,
getUserFlow,
];
// Little helper function to abstract going to different pages
export function* forwardTo(location) {
yield call(browserHistory.push, location);
}
Reducer.js
/*
* The reducer takes care of state changes in our app through actions
*/
import { fromJS } from 'immutable';
import auth from 'utils/auth';
import {
CHANGE_FORM,
SET_AUTH,
SENDING_REQUEST,
REQUEST_ERROR,
CLEAR_ERROR,
SET_USER,
CLEAR_USER,
} from './constants';
// The initial application state
const initialState = fromJS({
formState: {
email: '',
password: '',
},
error: '',
currentlySending: false,
user: {},
loggedIn: auth.loggedIn(),
});
// Takes care of changing the application state
function globalReducer(state = initialState, action) {
switch (action.type) {
case CHANGE_FORM:
return state.set('formState', action.newFormState);
case SET_AUTH:
return state.set('loggedIn', action.newAuthState);
case SET_USER:
return state.set('user', action.user.user);
case SENDING_REQUEST:
return state.set('currentlySending', action.sending);
case REQUEST_ERROR:
return state.set('error', action.error);
case CLEAR_ERROR:
return state.set('error', '');
case CLEAR_USER:
return state.set('user', {});
default:
return state;
}
}
export default globalReducer;
答案 0 :(得分:1)
你需要抛出错误:
return axios.post(url, transformRequest(data))
.then(response => {
cookie.save('token', response.data.token, { path: '/' });
cookie.save('email', response.data.user.email, { path: '/' });
return response.data;
})
.catch((error) => {
throw error;
});