Estoy aprendiendo React Redux con Create-React-App

Tengo problemas con la lógica de las tiendas, reductores, acciones, etc.

Tengo una página de inicio de sesión simple (se omitieron algunos JSX para que sea más fácil de leer)

Login.js

import React, { Component } from "react";
import { connect } from "react-redux";
import * as actions from '../../actions';
import Logo from "../img/image-center.png";
import "./login.css";


class Login extends Component {
  constructor(props){
    super(props);
    this.state = {
      errorMsg : ""
    };
    this.loginClicked = this.loginClicked.bind(this);   
    console.log("loggedIn:", this.props.login);
  }

  loginClicked() {
    try {
      this.props.loginUser(this.refs.email.value, this.refs.password.value)
      .then(() => {
        console.log("thisprops", this.props);        
      });
    }
    catch(ex){
      this.state.errorMsg = "Unable to connect to server";
      console.log("error", ex);
    }
  }

  render() {
    return (

      <div className="login-bg">
        <div className="container signForm">
            <div className="col s12 l6 login-form">
              <p className="center-align">Login to Trade Portal</p>
              <form>
                <div className="row">
                  <div className="input-field">
                    <input id="email" type="email" className="validate" ref="email" />
                    <label htmlFor="email">Email</label>
                  </div>
                </div>
                <div className="row">
                  <div className="input-field">
                    <input id="password" type="password" className="validate" ref="password" />
                    <label htmlFor="password">Password</label>
                  </div>
                </div>
                <div className="row">
                  <button
                    className="btn waves-effect waves-light"
                    type="button"
                    name="action"
                    onClick={this.loginClicked}
                    >
                    Submit
                  </button>
                  <a href="/subcontractor" className="register">
                    Register here
                  </a>
                </div>
                <div className="row"><div style={{textAlign: "center", color:"red"}}>{this.props.login.message}</div></div>   

              </form>
            </div>
          </div>
        </div>
      </div>
    );
  }
}


function mapStateToProps({login}){
  return { login } ;
}

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

Como puede ver, la función Log onClick llama a un prop loginUser que se deriva usando connect (y en realidad llama a mi método Action Login)

Acciones \ index.js

import axios from "axios";
import { FETCH_USER, LOGIN_USER, LOGIN_FAILED } from "./types";


export const fetchUser = () => async dispatch => {
  const res = await axios.get("/api/Account/GetUser");
  dispatch({ type: FETCH_USER, payload: res.data });
};

export const loginUser = (username, password) => async dispatch => {
    try {
        const res = await axios.post("/api/Account/Login", {username: username, password: password, persistant: false });
        const message = res.data ? "" : "Incorrect username or password";
        dispatch({ type: LOGIN_USER, payload: { success: res.data, message: message } });
    }
    catch(ex){
        console.log("Login Failed:", ex);
        dispatch({ type: LOGIN_FAILED, payload: { success: false, message: "Unable to connect to authentication server" } });
    }
}

El código anterior llama a mi servidor e inicia sesión en el usuario, cuando tiene éxito se lee en loginReducer.js

import { LOGIN_USER, LOGIN_FAILED } from "../actions/types";

export default function(state = null, action) {
  console.log(action);
  switch (action.type) {
    case LOGIN_USER:      
      return { success: action.payload.success, message: action.payload.message };
      break;
    case LOGIN_FAILED:
      return { success: false, message: action.payload.message };
      break;
      default:
    return { success: false, message: ""};
  }
}

Ahora mi pregunta es dónde y cómo redirijo al usuario al iniciar sesión correctamente en la página de inicio. "/Casa"

Espero poder hacerlo en Login.js en algún lugar, ya que un día podría querer tener 2 rutas de inicio de sesión (es decir, si inicia sesión desde un encabezado, puede que no redirija a inicio, pero al iniciar sesión desde Login.js debería iniciar sesión en casa). Por lo tanto, no creo que esta acción deba ir en Acción o Reductor. Pero no estoy seguro de cómo puedo vincularlo en Login.js, así que cuando inicie sesión correctamente, redirija

2
michael 17 ene. 2018 a las 09:01

3 respuestas

La mejor respuesta

Posibles formas

1- Redirigir desde el método loginClicked después de iniciar sesión correctamente (dentro de .then), así:

loginClicked() {
    try {
      this.props.loginUser(this.refs.email.value, this.refs.password.value)
      .then(() => {
          this.props.history.push('/home');       
      });
    }
    catch(ex){
      this.state.errorMsg = "Unable to connect to server";
      console.log("error", ex);
    }
}

2- u otra opción es poner el check dentro del método de renderizado, cada vez que ocurra algún cambio en la tienda, volverá a renderizar el componente y si encuentra la redirección success == true a la página de inicio, Like esta:

render(){

    if(this.props.success)
        return <Redirect to="/home" />

    return (....)
}

Si sigue el primer enfoque, debe poner la marca dentro del método componentDidMount también, si el usuario desea abrir la página de inicio de sesión después de iniciar sesión correctamente, redirija a la página de inicio. Está manteniendo la sesión de inicio de sesión mediante bool success verifique ese valor de bool.

componentDidMount(){
   if(this.props.success) {
      this.props.history.push('/home');
   }
}

Sugerencia :

Evite usar referencias de cadena, según DOC :

Si trabajó con React anteriormente, puede estar familiarizado con una API anterior donde el atributo ref es una cadena, como "textInput", y se accede al nodo DOM como this.refs.textInput. No lo recomendamos porque las referencias de cadenas tienen algunos problemas, se consideran heredadas y es probable que se eliminen en una de las versiones futuras. Si actualmente usa this.refs.textInput para acceder a las referencias, le recomendamos el patrón de devolución de llamada.

3
Mayank Shukla 17 ene. 2018 a las 06:32

Redux-thunk devolverá lo que devuelva de su thunk, lo que significa que si devuelve una promesa (que ya está haciendo porque es una función async), simplemente puede esperarla en Login.js y luego realizar la redirección .

Parece que podría simplemente modificar console.log("thisprops", this.props); en Login.js que se lleva a cabo después de llamar a loginUser para realizar la redirección.

0
casieber 17 ene. 2018 a las 06:11

Puede hacerlo en el ciclo de vida de reacción.

componentWillReceiveProps(nextProps) {
  if (nextProps.login.success && nexProps.login.success !== this.props.login.success) {
     this.props.history.push('/home');
  }
 }
0
soupette 17 ene. 2018 a las 18:39
48294505