Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Formulario de Login con Redux

17/29
Recursos

Aportes 24

Preguntas 6

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Creo que con éste paso del Login fue mucho más entendible la forma en qué se construye la forma de manejar la información con Redux:
Pensemos siempre en ésta imagen:

1. El componente: Siempre debe estar suscrito al Store para saber, por medio del reducer, cómo va a actualizar la información del estado. Esto significa que al tener esa conexión podemos realizar el envío (dispatch) de las acciones al Reducer.
2. Actions: Las acciones por sí solas son un sencillo objeto, que por buena práctica se retornan en una función. Esta función es pasada al Reducer para poder realizar la función / acción (action) que corresponde a la estructura de la aplicación.
3. El Reducer: Es la función que determina los cambios de estado de la aplicación. Es acá donde ocurren los cambios del estado (Store). Es una función pura que devuelve un objeto con el estado actual, después de haber ejecutado la acción que corresponda:

  • Si tiene un llamado por medio de una acción enviada desde el componente, ejecutará alguna acción que corresponda a la interacción del usuario
  • Si es la primera vez que se ejecuta, o sea el estado incial, igualmente ejecuta una acción, que se ve reflejada como el retorno del estado inicial, un estado default que devuelve el estado del Store.
    4. El Store: Es quién contiene el estado de todo el aplicativo, la única fuente de verdad (hablando en los términos de Redux), El sitio que contiene el estado del todo el aplicativo.
  • Tiene conexión con el Componente si éste se encuentra suscrito (o conectado), - Comprende las acciones enviadas desde el Componente para que el Reducer le diga cómo debería determinar su estado.
    .
    Espero les ayude, a mí me ayudó mucho.
    Les dejo algo de apoyo haciendo click acá

Por si acaso, si alguien tiene el formulario un componente con el formulario y no directamente en el login como lo hice yo van a necesitar un componente mágico de orden superior que se llama withRouter que permite añadir el history a un componente más profundo, dejo el ejemplo de mi código del LoginForm.

import React, { useState } from 'react';
import { connect } from 'react-redux';
import { Link, withRouter } from 'react-router-dom';
import { loginRequest } from '../actions';
import '../assets/styles/components/LoginForm.scss';

const LoginForm = (props) => {
  const [isChecked, setIsChecked] = useState(false);
  const [form, setValues] = useState({
    email: '',
  });

  const { history } = props;

  const handleInput = (event) => {
    setValues({
      ...form,
      [event.target.name]: event.target.value,
    });
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    props.loginRequest(form);
    history.push('/');
  };

  return (
    <div className='login-section__form-container'>
      <div className='login-section__form'>
        <h1 className='form__title'>Inicia sesión</h1>
        <form onSubmit={handleSubmit}>
          <input aria-label='Campo de usuario para iniciar sesión' className='input__text' type='text' id='user' name='email' placeholder='Usuario o email' onChange={handleInput} />
          <input aria-label='Campo de contraseña secreta para iniciar sesión' className='input__text' type='password' id='pass' name='pass' placeholder='Contraseña' onChange={handleInput} />
          <label className={isChecked ? 'input__check--label label-checked' : 'input__check--label input__check--label-before'} htmlFor='remember'>
            <input onClick={() => setIsChecked(!isChecked)} className='input__check' type='checkbox' name='remember' id='remember' />
            Recordar sesión
          </label>
          <button className='main-btn form-submit' type='submit'>Iniciar sesión</button>
        </form>

        <div className='remember-password__container'>
          <Link className='remember-password__btn' to='/'>¿Haz olvidado tu contraseña?</Link>
        </div>
      </div>
    </div>
  );
};

const mapDispatchToProps = {
  loginRequest,
};

export default withRouter(connect(null, mapDispatchToProps)(LoginForm));

Como se dará cuenta, llamo a withRouter desde ‘react-router-dom’, recibo el history por los props y luego exporto el componente con withRouter.

recuerden que el boton debe de ser tipo ‘submit’ si no no va a funcionar su login

<button className='button' type='submit'>Iniciar sesión</button>```

Les comparto este codigo que utilice en el header para poder mostrar el nombre de nuestro ususario en el header una vez que ya haya iniciado sesion

y aqui el codigo

import React from 'react';
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import '../assets/styles/components/Header.scss';
import logo from '../assets/images/logo-platzi.png';
import userIcon from '../assets/images/profile-user.svg';

const Header = ({ user }) => {
   console.log(user.email)
   return(
   <header className="header">
      <Link to="/"> 
         <img className="header__img" src={ logo } alt="" />
      </Link> {/* Usamos el elemento link de react router dom, ya que nos permite poder
      desplazarnos por nuestra aplicacion sin necesidad de hacer un refres a la pagina completa */}
      <div className="header__menu">
         <div className="header__menu--profile">
            <img src={ userIcon } alt="user icon" />
            <p>Perfil</p>
         </div>
         {user.email !== undefined ?
            <ul>
               <li><p>Bienvenido <b>{user.email}</b></p></li>
               <li><p>Mi perfil</p></li>
               <li><Link to="/register">Registro</Link></li>
            </ul>
            :
            <ul>
               <li><Link to="/login">Iniciar sesion</Link></li>
            </ul>
         }
      </div>
      
   </header>
)};

const mapStateToProps = state => {
   return {
      user: state.user,
   }
}
export default connect(mapStateToProps,null)(Header);

props.history.push('/')

estupendo, me esta gustando cada día mas react, tengo que ponerme más autodidacta 😄

¿por qué no puedo acceder a user desde props como hago con las otras variables?

const { user, myList, trends, originals } = props;

si imprimo por consola user, me dice que no esta definido, ¿como podria acceder a ese valor?
al mostar props por cosola puedo ver las variables: myList, trends y original, pero no las otras variables que estan en el initialState

usando redux-dev-tool veo que si esta funcionando los reducer, pero sigo sin entender por qué no puedo acceder a los otros datos del inicialState


Súper genial!!
prácticas:

como puede ver lo que tengo en el estado? para ver al usuario que se agrega

Buena clase Profe, comprendì muy bien lo que explicaste!!! Estoy muy feliz de seguir aprendiendo Programación !!!

Vamos a mandar nuestra información a nuestro estado con Redux. Aquí simulamos un login.

index.js de actions:

export const loginRequest = (payload) => ({
  type: actions.loginRequest,
  payload,
});

Login.jsx:

import { loginRequest } from '../actions'; //*No haec falta escribir el index porque ya se entiende que se quiere ese archivo al tener ese nombre

const Login = (props) => {

  const handleSubmit = (event) => {
    event.preventDefault(); //*Para que no se haga la acción de enviar formulario
    props.loginRequest();
    props.history.push('/'); //*Redirigimos al usuario al home
  };
};

const mapDispatchToProps = {
  loginRequest,
};

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

index.js de reducers:

case actions.loginRequest:
  return {
    ...state,
    user: action.payload,
  };

Hola… tengo una duda a quien no le guarda la información en el store?

Saben cuál es el curso de autentificación de la escuela de JavaScrip? 😄

``
Hola, props.history.push('/') no me sirvió, pero hoy 2022 encontré una solución en https://stackoverflow.com/questions/70374596/this-props-history-push-isnt-redirecting-me-to-homepage 

En resumen lo que hice fue:

Entonces:
1.	Importamos useNavigate de react router dom
2.	Luego creamos la función withRouter, que recibirá un componente.
3.	Luego dentro de esa función, creamos otra llamada ComponentWithRouterProp, que recibirá a props.
4.	Dentro, creamos la constante navigate, que será igual al hook useNavigate.
5.	Esto retornará al componente, con todas las propiedades y la funcionalidad para navegar
6.	Luego se retornará la función ComponentWithRouterProp.
7.	En handle submit, cambiaremos history por navigate, entonces quedará props.navigate(‘/’);
8.	Finalmente, el export default será:
export default (withRouter(connect(null, mapDispatchToProps)(Login))

Comparto el código:

```
import React, {useState} from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import Header from '../components/Header';
import { loginRequest } from '../actions/index';
import '../assets/styles/components/Login.scss';
import googleIcon from '../assets/static/google-icon.png';
import twitterIcon from '../assets/static/twitter-icon.png';
import { useNavigate } from "react-router-dom";

  function withRouter(Component) {
    function ComponentWithRouterProp(props) {
      const navigate = useNavigate();
      return (
        <Component
          {...props}
          navigate={navigate}
        />
      );
    }
  
    return ComponentWithRouterProp;
  }
const Login = (props) => {
    const [form, setValues] = useState({
        email : '',
    })
    const handleInput= event => {
        setValues({
            ...form,
            [event.target.name]: event.target.value
        })
    }
    const handleSubmit = event => {
        event.preventDefault();
        props.loginRequest(form);
        props.navigate('/');
    }
    return (
        <>
        <Header isLogin />
        <section className="login">
            <section className="login__container">
            <div>
                <h2>Inicia sesión</h2>
                <form className="login__container--form"
                    onSubmit={handleSubmit}
                >
                <input
                    name="email"
                    className="inputform"
                    type="text"
                    placeholder="Correo"
                    onChange={handleInput}
                />
                <input
                    name="password"
                    className="inputform"
                    type="password"
                    placeholder="Contraseña"
                    onChange={handleInput}
                />
                <button className="button" type="submit">Iniciar sesión</button>
                <div className="login__container--remember-me">
                    <label>
                    <input type="checkbox" id="cbox1" value="first_checkbox" /> Recuérdame
                    </label>
                    <a href="/">Olvidé mi contraseña</a>
                </div>
                </form>
                <section className="login__container--social-media">
                <div><img src={googleIcon} /> Inicia sesión con Google</div>
                <div><img src={twitterIcon} /> Inicia sesión con Twitter</div>
                </section>
                <p className="login__container--register">
                    No tienes ninguna cuenta {' '}
                    <Link to="/register">
                    Regístrate
                    </Link>
                </p>
            </div>
            
            </section>
        </section>
        </>
    );
}

const mapDispatchToProps = {
    loginRequest,
}
export default (withRouter(connect(null, mapDispatchToProps)(Login)));

```

cambios en el history con la v6 de react-router-dom

import React, {useState} from "react";
import { connect } from "react-redux";
import {Link,useNavigate  } from "react-router-dom";
import { loginRequest } from "../actions";

import googleIcon from "../assets/static/google-icon.png";
import twitterIcon from "../assets/static/twitter-icon.png";
import '../assets/styles/components/Login.scss'

const Login = props => {
    let navigate = useNavigate();
    const [form, setValues] = useState({
        email: '',
    });

    const handleInput = event => {
        setValues({
            ...form,
            [event.target.name]: event.target.value
        })
    }

    const handleSubmit = event => {
        event.preventDefault();
        props.loginRequest(form);
        console.log(form);
        navigate('/');
    }

    return (
        <section className="login">
            <section className="login__container">
                <h2>Inicia sesión</h2>
                <form className="login__container--form" onSubmit={handleSubmit}>
                    <input
                        name="email"
                        className="input" 
                        type="text" 
                        placeholder="Correo"
                        onChange={handleInput}
                    />
                    <input
                        name="password" 
                        className="input" 
                        type="password" 
                        placeholder="Contraseña"
                        onChange={handleInput}
                    />
                    <button className="button" type='submit '>Iniciar sesión</button>
                    <div className="login__container--remember-me">
                    <label>
                        <input type="checkbox" id="cbox1" value="first_checkbox" />Recuérdame
                    </label>
                    <a href="/">Olvidé mi contraseña</a>
                    </div>
                </form>
                <section className="login__container--social-media">
                    <div><img src={googleIcon}/> Inicia sesión con Google</div>
                    <div><img src={twitterIcon}/> Inicia sesión con Twitter</div>
                </section>
                <p className="login__container--register">
                    No tienes ninguna cuenta 
                    <Link to="/register">
                        Regístrate
                    </Link>
                </p>
            </section>
        </section>
    );
};

const mapDispatchToProps = {
    loginRequest,
}

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

Ahora conectaremos con REDUX y como ya sabemos que tenemos que importar el connect para importar de forma diferente nuestro componente. Que por mientras son Nulls

export default connect (null, null)(Login);

Ahora en actions vamos a crear la accion

export const loginRequest = (payload) => ({
  type: "LOGIN_REQUEST",
  payload,
});

Y ahora lo importamos en nuestro archivo. Ahora haremos nuestro mapDIspatchToProps y cambiaremos nuestro export por

const mapDispatchToProps = {
  loginRequest,
};

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

Ya que tengamos todo, solo tenemos que agregarle props a nuestro componente, y cambiar la funcion de HandleSubmit por

const handleSubmit = (event) => {
    event.preventDefault();
    props.loginRequest(form);
  };

Pero agregaremos la ruta donde podamos irnos al home despues de logearnos de forma exitosa. Esto lo haremos con los props y la propiedad history y con el metodo push podemos redirigirnos a cualquier ruta, en este caso el home:

const handleSubmit = (event) => {
    event.preventDefault();
    props.loginRequest(form);
    props.history.push("/");
  };

Tambien hay que agregar nuestro reducer para que todo funcione.

case "LOGIN_REQUEST":
      return {
        ...state,
        user: action.payload,
      };

Donde le decimos que todo nuestro payload se agregue a user

Les dejo algo de lo que en definitiva, dicho por muchos compañeros, es mejor tener las variables constantes a parte y llamarlas para evitar Typos y demás… llevaba mucho tiempo buscando solución a que no me ejecutaba el dispatch de requestLogin y resultó ser un typo en los reducers.
Les dejo mi opción de solución:

  1. Creo un archivo constants.js dentro de ./src/utils/ y queda así:
  2. Los llamo desde ./src/reducers/ y ./src/actions/ y quedan así:

actions.js

import { SET_FAVORITE, DELETE_FAVORITE, LOGIN_REQUEST } from '../utils/constants';

export const setFavorite = (payload) => ({
  type: SET_FAVORITE,
  payload,
});

export const deleteFavorite = (payload) => ({
  type: DELETE_FAVORITE,
  payload,
});

export const loginRequest = (payload) => ({
  type: LOGIN_REQUEST,
  payload,
});

reducers.js

import { SET_FAVORITE, DELETE_FAVORITE, LOGIN_REQUEST } from '../utils/constants';

const reducer = (state, action) => {
  const existsFavorite = state.myList.find((item) => item.id === action.payload.id);

  switch (action.type) {
    case SET_FAVORITE:
      //if the item already exists in the state
      if (existsFavorite) {
        return {
          ...state,
        };
      }
      //return the item that is being added alongside the state
      return {
        ...state,
        myList: [...state.myList, action.payload],
      };

    case DELETE_FAVORITE:
      return {
        ...state,
        myList: state.myList.filter((item) => item.id !== action.payload),
      };

    case LOGIN_REQUEST:
      return {
        ...state,
        user: action.payload,
      };

    default:
      return state;
  }
};

export default reducer;

Login.jsx

import React, { useState } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { loginRequest } from '../actions';
import googleIcon from '../assets/img/google-icon.png';
import twitterIcon from '../assets/img/twitter-icon.png';
import '../assets/styles/containers/Login.scss';

const Login = (props) => {
  const [formValues, setFormValues] = useState({
    email: '',
    password: '',
  });
  const handleInput = (event) => {
    setFormValues({
      ...formValues,
      [event.target.name]: event.target.value,
    });
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    props.loginRequest(formValues);
    //redirect Home:]
    props.history.push('/');

  };

  return (
    <section className='Login'>
      <section className='Login__container'>
        <h2>Inicia sesión</h2>
        <form
          className='Login__container--form'
          action=''
          onSubmit={handleSubmit}
        >
          <input
            className='input'
            type='text'
            name='email'
            id='email'
            placeholder='Correo'
            onChange={handleInput}
          />
          <input
            className='input'
            type='password'
            name='password'
            id='password'
            placeholder='Contraseña'
            onChange={handleInput}
            autoComplete='on'
          />
          <button className='button' type='submit'>Iniciar sesión</button>
          <div className='Login__container--remember-me'>
            <label htmlFor='cbox1'>
              <input type='checkbox' name='cbox1' id='cbox1' value='Checkbox' />
              Recuérdame
            </label>
            <Link to='/forgot-password'>
              Olvidé mi contraseña
            </Link>
          </div>
        </form>
        <section className='Login__container--social-media'>
          <div>
            <img src={googleIcon} alt='Google' />
            inicia sesión con Google
          </div>
          <div>
            <img src={twitterIcon} alt='Twitter' />
            inicia sesión con Twitter
          </div>
        </section>
        <p className='Login__container--register'>
          No tienes ninguna cuenta?
          <Link to='/register'>
            Regístrate
          </Link>
        </p>
      </section>
    </section>
  );
};

const mapDispatchToProps = {
  loginRequest,
};

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

Como podría crear un archivo logs en deploy ?

de donde sale el user? ups, me perdí ahí si me perdí

Hola, si quisiera enviar esos datos para validar usuario y password contra una base de datos o API qué opciones tengo? Voy llevando el curso bien, pero todavia estoy algo verde con React y javascript .

b

Gracias 😄