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 鈥榬eact-router-dom鈥, recibo el history por los props y luego exporto el componente con withRouter.

recuerden que el boton debe de ser tipo 鈥榮ubmit鈥 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 馃槃