React / Redux reducer不会从promise

时间:2017-12-14 20:20:42

标签: javascript reactjs redux redux-saga

在我的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;

1 个答案:

答案 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;
      });