login api request using react and redux

2019-08-16 14:59发布

问题:

I'm trying to make a small project using react & redux. The Main page for this project is the login. I already have a working api for login. Below is the code snippets from my project:

login.js

onLoginFormSubmit(event) {
    event.preventDefault();
    this.props.actions.login(this.state.username, this.state.password);
  }

render() {
    return (
      ...Login Form ...
    );
  }
}

Login.propTypes = {
  actions: PropTypes.object.isRequired,

};

function mapStateToProps(state, ownProps) {
  return {
    loginResponse: state.loginResponse
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(loginAction, dispatch)
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Login);

loginReducer.js

import {
  LOGIN_SUCCESS,
  LOGIN_FAILED,
  LOGIN_ATTEMPT
} from '../actions/type';
import Immutable from 'immutable';

const initialState = new Immutable.Map({
  username: '',
  password: '',
  isLoggingIn: false,
  isLoggedIn: false,
  error: null
});

export default function user(state = initialState, action){
  switch (action.type){
    case LOGIN_ATTEMPT:
      console.log("LOGIN_ATTEMPT: ",action.user);
      return state.merge({
        isLoggingIn: true,
        isLoggedIn: false,
        username: action.user.username,
        password: action.user.password
      });

    case LOGIN_FAILED:
      console.log("LOGIN_FAILED: ");
      return state.merge({
        error: action.error,
        isLoggingIn: false,
        isLoggedIn: false
      });

    case LOGIN_SUCCESS:
      console.log("LOGIN_SUCCESS: ",action);
      return state.merge({
        error: null,
        isLoggingIn: false,
        isLoggedIn: true
      })
      break;

    default:
      return state;

  }
}

loginAction.js

export function loginError(error){
  return  { error, type: LOGIN_FAILED };
}

export function loginSuccess(response){
  return dispatch => {
    dispatch({ response, type: LOGIN_SUCCESS});
  };
}

export function loginRequest(username, password){
  const user = {username: username, password: password};
  return { user, type: LOGIN_ATTEMPT };
}


export function login(username, password) {
  console.log("User Data: ", username, password);
    return dispatch =>
    fetch('http://192.168.1.100:9090/login', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        username: username,
        password: password
      }),
    })
    .then(response => {
      console.log("I'm here");
      if(response.status >= 200 && response.status < 300){
        console.log("Response; ", response);
        dispatch(loginSuccess(response));
      } else {
        const error = new Error(response.statusText);
        error.response = response;
        dispatch(loginError());
        throw error;
      }
    })
    .catch(error => { console.log('Request Failed: ', error);});
  }

The problem is, the login api is not being called. The only error I'm getting in my console is Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.

I know there's redux-thunk for async calls, but don't know how to make it work with it. I'm still learning. So any help will be appreciated.

Thanks.

回答1:

DOCS:

npm install --save redux-thunk

Then, to enable Redux Thunk, use applyMiddleware():

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

// Note: this API requires redux@>=3.1.0
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);


回答2:

For async actions to work, you can use redux-thunk. To use it is pretty simple. Just load it into your middleware when you create your store.

import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers';

export default (initialState = {}) => {

  return createStore(
    rootReducer,
    initialState,
    applyMiddleware(thunk)
  );

};