Reactjs React/Redux:如何保持登录失败

Reactjs React/Redux:如何保持登录失败,reactjs,redux,react-router,react-redux,Reactjs,Redux,React Router,React Redux,我是React/Redux的初学者,我试图在现有的代码中做一些事情,只是为了了解它是如何工作的。我要编辑的部分是连接部分。就像现在一样,如果登录名和密码都正常,你就进入一个新页面,如果没有,它什么也不做 我尝试做的唯一简单的事情就是向用户显示他们的登录信息是错误的,例如在字段上添加一个红色边框 这是我添加的代码,我会尽量不向您展示无用的代码,也不会忘记有用的代码,但是如果您需要更多,请告诉我 我做的第一件事是为actionTypes.js中的错误添加一个常量: export const AUTH

我是React/Redux的初学者,我试图在现有的代码中做一些事情,只是为了了解它是如何工作的。我要编辑的部分是连接部分。就像现在一样,如果登录名和密码都正常,你就进入一个新页面,如果没有,它什么也不做

我尝试做的唯一简单的事情就是向用户显示他们的登录信息是错误的,例如在字段上添加一个红色边框

这是我添加的代码,我会尽量不向您展示无用的代码,也不会忘记有用的代码,但是如果您需要更多,请告诉我

我做的第一件事是为actionTypes.js中的错误添加一个常量:

export const AUTH_REQUEST = 'AUTH_REQUEST';
export const AUTH_RECEIVE = 'AUTH_RECEIVE';
export const AUTH_ERROR = 'AUTH_ERROR';
const initialState = {
  authToken: '',
  isFetching: false,
  error: false,
  errorMessage: ''
}

export default function (state=initialState, action) {
  switch (action.type) {
    case actionType.AUTH_REQUEST:
      return {
        ...state,
        isFetching: true
      };
    case actionType.AUTH_RECEIVE:
      return authLogin(state, action);
    case actionType.AUTH_ERROR:
      return {
        ...state,
        error: true,
        errorMessage: 'Incorrect login or password!'
      };
  }
  return state;
}

function authLogin(state, action) {
  const { authToken } = action;
  return {
    ...state,
    isFetching: false,
    authToken
  };
}
import * as actions from './actions/auth.js';
import Login from './presenter';

const mapStateToProps = (state) => {
  return {
    error: state.login.error,
    errorMessage: state.login.errorMessage,
  };
};
const mapDispatchToProps = (dispatch) => {
  return {
    onAuth: (email, password) => {
      dispatch(actions.fetchLogin(email, password));      
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Login); // maps your state to your component's props
const initialState = {
  authToken: '',
  isFetching: false,
  error: false,
  errorMessage: ''
}

export default function loginReducer(state=initialState, action) {
  switch (action.type) {
    case actionType.AUTH_REQUEST:
      return {
        ...state,
        isFetching: true
    };
    case actionType.AUTH_RECEIVE:
      return authLogin(state, action);
    case actionType.AUTH_ERROR:
      return {
        ...state,
        error: true,
        errorMessage: 'Incorrect login or password!'
      };
  }
  return state;
}

function authLogin(state, action) {
  const { authToken } = action;
  return {
    ...state,
    isFetching: false,
    authToken
  };
}
然后在actions/auth.js中,我添加了authError函数,并在服务器响应失败后调用它:

function authRequest() {
  return {
    type: actionTypes.AUTH_REQUEST
  };
}

function authReceive(authToken) {
  return {
    type: actionTypes.AUTH_RECEIVE,
    authToken
  };
}

function authError() {
  return {
    type: actionTypes.AUTH_ERROR
  };
}

export function fetchLogin(email, password) {
  return function (dispatch) {
    dispatch(authRequest());

    const urlApi = `//${AUTH_BACKEND_HOST}:${AUTH_BACKEND_PORT}/${AUTH_BACKEND_URL.login}`
    fetch(urlApi, {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'content-type': 'application/json'
      },
      body: JSON.stringify({
        email,
        password
      })
    })
    .then((response) => {
      if(response.ok) {
        // SUCCESS
        response.json().then(function(json) {
          dispatch(authReceive(json.key));
          dispatch(push('/'));
        });
      } else {
        // FAIL
        response.json().then(function(json) {
          dispatch(authError());
        });
      }
    })
    .catch(function(ex) {
      console.log(ex);
    });
  };
}
现在,在reducers/auth.js中:

export const AUTH_REQUEST = 'AUTH_REQUEST';
export const AUTH_RECEIVE = 'AUTH_RECEIVE';
export const AUTH_ERROR = 'AUTH_ERROR';
const initialState = {
  authToken: '',
  isFetching: false,
  error: false,
  errorMessage: ''
}

export default function (state=initialState, action) {
  switch (action.type) {
    case actionType.AUTH_REQUEST:
      return {
        ...state,
        isFetching: true
      };
    case actionType.AUTH_RECEIVE:
      return authLogin(state, action);
    case actionType.AUTH_ERROR:
      return {
        ...state,
        error: true,
        errorMessage: 'Incorrect login or password!'
      };
  }
  return state;
}

function authLogin(state, action) {
  const { authToken } = action;
  return {
    ...state,
    isFetching: false,
    authToken
  };
}
import * as actions from './actions/auth.js';
import Login from './presenter';

const mapStateToProps = (state) => {
  return {
    error: state.login.error,
    errorMessage: state.login.errorMessage,
  };
};
const mapDispatchToProps = (dispatch) => {
  return {
    onAuth: (email, password) => {
      dispatch(actions.fetchLogin(email, password));      
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Login); // maps your state to your component's props
const initialState = {
  authToken: '',
  isFetching: false,
  error: false,
  errorMessage: ''
}

export default function loginReducer(state=initialState, action) {
  switch (action.type) {
    case actionType.AUTH_REQUEST:
      return {
        ...state,
        isFetching: true
    };
    case actionType.AUTH_RECEIVE:
      return authLogin(state, action);
    case actionType.AUTH_ERROR:
      return {
        ...state,
        error: true,
        errorMessage: 'Incorrect login or password!'
      };
  }
  return state;
}

function authLogin(state, action) {
  const { authToken } = action;
  return {
    ...state,
    isFetching: false,
    authToken
  };
}
到目前为止,当我在Firefox中检查它时,它似乎是有效的。状态包含错误和错误消息值

下面是我的组件/Login/presenter.jsx,我认为它将根据状态显示正确的HTML:

import React from 'react';

const Login = React.createClass({

  handleSubmit(event) {
    event.preventDefault()

    const email = this.refs.email.value
    const password = this.refs.password.value

    this.props.onAuth(email, password);
  },

  render() {
    const { errorMessage } = this.props

      return (
        <form onSubmit={this.handleSubmit}>
          <label>Email <input ref="email" placeholder="email" required /></label>
          <label>Password <input ref="password" placeholder="password" type="password" required /></label><br />
          <p>{errorMessage}</p>
          <button type="submit">Login</button>
        </form>
      )    
  }    
});

export default Login;

编辑:问题之一似乎是我没有将状态映射到道具。我尝试了Mael Razavet和azium的答案,在Login/index.js中添加了mapStateToProps:

import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as actions from '../../actions';
import Login from './presenter';

function mapDispatchToProps(dispatch) {
  return {
    onAuth: bindActionCreators(actions.fetchLogin, dispatch)
  };
}

function mapStateToProps (state) {
  return {
    errorMessage: state.errorMessage
  };
}

export default connect(mapStateToProps, mapDispatchToProps) (Login);
但似乎errorMessage仍然没有定义


谢谢。

我想你忘了把你的状态映射到道具上。在您的情况下,您应该将此内容添加到组件/Login/index.js

export const AUTH_REQUEST = 'AUTH_REQUEST';
export const AUTH_RECEIVE = 'AUTH_RECEIVE';
export const AUTH_ERROR = 'AUTH_ERROR';
const initialState = {
  authToken: '',
  isFetching: false,
  error: false,
  errorMessage: ''
}

export default function (state=initialState, action) {
  switch (action.type) {
    case actionType.AUTH_REQUEST:
      return {
        ...state,
        isFetching: true
      };
    case actionType.AUTH_RECEIVE:
      return authLogin(state, action);
    case actionType.AUTH_ERROR:
      return {
        ...state,
        error: true,
        errorMessage: 'Incorrect login or password!'
      };
  }
  return state;
}

function authLogin(state, action) {
  const { authToken } = action;
  return {
    ...state,
    isFetching: false,
    authToken
  };
}
import * as actions from './actions/auth.js';
import Login from './presenter';

const mapStateToProps = (state) => {
  return {
    error: state.login.error,
    errorMessage: state.login.errorMessage,
  };
};
const mapDispatchToProps = (dispatch) => {
  return {
    onAuth: (email, password) => {
      dispatch(actions.fetchLogin(email, password));      
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Login); // maps your state to your component's props
const initialState = {
  authToken: '',
  isFetching: false,
  error: false,
  errorMessage: ''
}

export default function loginReducer(state=initialState, action) {
  switch (action.type) {
    case actionType.AUTH_REQUEST:
      return {
        ...state,
        isFetching: true
    };
    case actionType.AUTH_RECEIVE:
      return authLogin(state, action);
    case actionType.AUTH_ERROR:
      return {
        ...state,
        error: true,
        errorMessage: 'Incorrect login or password!'
      };
  }
  return state;
}

function authLogin(state, action) {
  const { authToken } = action;
  return {
    ...state,
    isFetching: false,
    authToken
  };
}
在您的还原程序/auth.js中:

export const AUTH_REQUEST = 'AUTH_REQUEST';
export const AUTH_RECEIVE = 'AUTH_RECEIVE';
export const AUTH_ERROR = 'AUTH_ERROR';
const initialState = {
  authToken: '',
  isFetching: false,
  error: false,
  errorMessage: ''
}

export default function (state=initialState, action) {
  switch (action.type) {
    case actionType.AUTH_REQUEST:
      return {
        ...state,
        isFetching: true
      };
    case actionType.AUTH_RECEIVE:
      return authLogin(state, action);
    case actionType.AUTH_ERROR:
      return {
        ...state,
        error: true,
        errorMessage: 'Incorrect login or password!'
      };
  }
  return state;
}

function authLogin(state, action) {
  const { authToken } = action;
  return {
    ...state,
    isFetching: false,
    authToken
  };
}
import * as actions from './actions/auth.js';
import Login from './presenter';

const mapStateToProps = (state) => {
  return {
    error: state.login.error,
    errorMessage: state.login.errorMessage,
  };
};
const mapDispatchToProps = (dispatch) => {
  return {
    onAuth: (email, password) => {
      dispatch(actions.fetchLogin(email, password));      
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Login); // maps your state to your component's props
const initialState = {
  authToken: '',
  isFetching: false,
  error: false,
  errorMessage: ''
}

export default function loginReducer(state=initialState, action) {
  switch (action.type) {
    case actionType.AUTH_REQUEST:
      return {
        ...state,
        isFetching: true
    };
    case actionType.AUTH_RECEIVE:
      return authLogin(state, action);
    case actionType.AUTH_ERROR:
      return {
        ...state,
        error: true,
        errorMessage: 'Incorrect login or password!'
      };
  }
  return state;
}

function authLogin(state, action) {
  const { authToken } = action;
  return {
    ...state,
    isFetching: false,
    authToken
  };
}
然后,在代码中,您应该组合减速器,如:

import { combineReducers, createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import Login from './components/Login';
import login from './reducers/auth.js'; //import your default reducer function

//COMBINE REDUCERS
const reducers = combineReducers({
  //reducers go here 
  login, //name of your reducer => this is is why your access your state like state.login
});

//WRAP WITH STORE AND RENDER
const createStoreWithMiddleware = applyMiddleware()(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <Login/>
  </Provider>
  , document.querySelector('.container'));
此errorMessage来自reducer中管理的状态,可在组件中用作This.props.errorMessage

以下是帮助我理解React中Redux的教程链接:
它应该可以帮助您更好地理解工作流

您从哪里传递
错误消息
道具?正如Mael Razavet指出的,似乎这可能是问题所在。即使我不知道这是什么意思。我想我不理解React/Redux应用程序中的工作流:|这就是您如何将更改(以及更普遍的信息)从您的应用商店中获取到您的组件以供使用。它基本上就是把你正在用还原器更新的存储区映射到道具上,这样你的组件就可以使用它了。你是说当你得到状态时,你需要把它映射到道具上,这样你就可以使用道具了?但是我应该在哪里写呢?在Login/index.jsx文件中,我有一个mapDispatchToProps函数,我假设它绑定了一个操作,并且我有一个导出默认连接(null,mapDispatchToProps)(Login);,老实说,我甚至不知道是什么,但我想我不可能在同一个jsx中有两个导出默认连接。非常接近,只需将
null
替换为
mapstatetops
。connect有两个参数第一个是这个答案中的参数对不起,我在帖子中忘了一些东西:presenter.jsx和index.jsx在登录文件夹中,我认为index.jsx导入presenter.jsx,所以azium的答案可能是正确的。另外,我犯了一些错误,没有actions.js或reducers.js文件,但actions和reducer是包含index.js和其他内容的文件夹。你能检查一下我的编辑并告诉我吗?因为我尝试了你的两个答案,但仍然无法成功。@azium谢谢你,我编辑了我的帖子,加入了关于/Login/index.js的部分。我尝试了你的答案,但errorMessage仍然没有定义。我可能完全错了。我编辑了我的答案,添加了您的操作和您的调度之间的映射。告诉我它是否有效?