Bienvenido al curso

1

Conoce a tu profesor y todo lo que aprenderás sobre Redux

2

¿Qué conocimientos me recomiendan para tomar este curso?

Repaso React

3

¿Qué es React y cómo funciona?

4

Preparando nuestro entorno de trabajo

5

Creación de la app con React

6

Agregando funciones a la app con React

7

Stateful vs Stateless

8

Ciclo de vida de React

9

Manejando promesas

10

React Router DOM

Introducción a Redux

11

¿Qúe es Redux, cuándo usarlo y por qué?

Fases de Redux

12

Introducción: las fases de Redux

13

Store

14

Reducers

15

Conexión a un componente

16

Action Creators

17

Redux Thunk

18

Explicación teórica: ciclo completo de Redux

19

Práctica: ciclo completo de Redux

Fases Extra

20

Archivos Types

21

Try Catch

22

Escenarios asíncronos

23

Componente Spinner

24

Componente Fatal

25

Tabla como componente

Compartir información en Redux

26

Introducción Compartir información en Redux

27

Parámetros por URL

28

Compartir Reducer

29

Múltiples Reducers

30

Llamando a múltiples reducers en una acción

31

Uso del estado en la acción

32

Evitar segundas búsquedas

33

Inmutabilidad

34

Evitar sobrescritura

35

Validación compuesta

36

Validación de errores

37

Modificando respuesta de url

38

Estado con interacción

39

Mostrar componentes dinámicamente

40

Llamadas asincronas dinámicas

41

Props por herencia vs estado

42

Estado compartido

Métodos HTTP

43

Introducción a métodos HTTP

44

Nuevo ciclo Redux

45

Normalizar datos

46

Mapear Objetos

47

Componente para agregar tarea

48

Manejar inputs con Reducer

49

POST

50

Deshabilitando botón

51

Redireccionar

52

Reutilizar componentes

53

PUT

54

DELETE

55

Últimos detalles

Conclusión

56

Conocimientos adquiridos

57

Qué hacer a continuación

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Curso de Redux por Bedu

Curso de Redux por Bedu

Rodolfo Saldivar

Rodolfo Saldivar

Llamando a múltiples reducers en una acción

30/57
Recursos

Aportes 28

Preguntas 3

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Regístrate o inicia sesión para participar.

Un consejo para quienes opinan que era mejor cambiar los nombres de los actions desde un principio, aunque es la solución mas facil para evitarse este tipo de ambiguedades, creo que es una gran oportunidad para aprender a resolver este tipo de situaciones cuando esto sucedan.

Si lo ven como si siempre fueran a trabajar desarrollos propios vale, pero si llegan a un equipo de desarrollo van a llegar muchas veces a trabajar sobre ciertas reglas de referenciación o manteniendo código de otros desarrolladores y parte del estandar es programar todo en inglés lo que aumenta la probabilidad de encontrarse la función getAll() para la obtención de múltiples recursos y no va a ser el único caso, así que es bueno saber como solucionar este problema.

Hola, también encontré un poco confusa esta clase, creo que para alguien sin mucha experiencia en Redux (como yo) sería mas fácil comenzar con nombres diferentes tanto en las funciones exportadas en los Actions así como nombrar diferente los casos en los reducers.
La diferencia seria importes desestructurados en lugar de import * as …
y tener que usar mapDispatchToProps incluso si solo hay uno. (ver código de Usuarios/index.js)

Les dejo el código para que lo vean y (espero) se entienda mejor.
En lo personal encuentro esta manera más fácil de digerir pero es bueno conocer diferentes aproximaciones!!.

// publicationsTypes.js

export const GET_PUBLICATIONS = "get_publications";
export const LOADING = "loading";
export const ERROR = "error";

// usuariosTypes.js

export const GET_USERS = "get_users";
export const LOADING = "loading";
export const ERROR = "error";

// usuariosActions.js

import axios from "axios";
import { GET_USERS, LOADING, ERROR } from "../types/usuariosTypes";

/* Una funcion que retorna otra función*/
export const getUsers = () => async dispatch => {
  dispatch({
    type: LOADING
  });
  try {
    const respuesta = await axios.get(
      "https://jsonplaceholder.typicode.com/users"
    );
    //console.log(respuesta.data);

    dispatch({
      type: GET_USERS,
      payload: respuesta.data
    });
  } catch (err) {
    console.error("Error: ", err.message);
    dispatch({
      type: ERROR,
      payload: err.message
    });
  }
};

// publicacionesActions.js

import axios from "axios";

import { GET_PUBLICATIONS, LOADING, ERROR } from "../types/publicacionesTypes";

export const getPublications = () => async dispatch => {
  dispatch({
    type: LOADING
  });
  try {
    const respuesta = await axios.get(
      "https://jsonplaceholder.typicode.com/posts"
    );

    dispatch({
      type: GET_PUBLICATIONS,
      payload: respuesta.data
    });
  } catch (err) {
    console.error("Error: ", err.message);
    dispatch({
      type: ERROR,
      payload: err.message
    });
  }
};

// usuariosReducer.js

import { GET_USERS, LOADING, ERROR } from "../types/usuariosTypes";

const INITIAL_STATE = {
  usuarios: [],
  loading: false,
  error: ""
};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case GET_USERS:
      return { ...state, usuarios: action.payload, loading: false };
    case LOADING:
      return { ...state, loading: true };

    case ERROR:
      return { ...state, error: action.payload, loading: false };

    default:
      return state;
  }
};

// publicacionesReducer.js

import { GET_USERS, LOADING, ERROR } from "../types/usuariosTypes";

const INITIAL_STATE = {
  usuarios: [],
  loading: false,
  error: ""
};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case GET_USERS:
      return { ...state, usuarios: action.payload, loading: false };
    case LOADING:
      return { ...state, loading: true };

    case ERROR:
      return { ...state, error: action.payload, loading: false };

    default:
      return state;
  }
};

// Usuarios/index.js

import React, { Component } from "react";
import { connect } from "react-redux";
import { getUsers } from "../../actions/usuariosActions";
import Spinner from "../general/Spinner";
import Fatal from "../general/Fatal";
import Tabla from "./Tabla";

class Usuarios extends Component {
  componentDidMount() {
    this.props.getUsers();
  }
  ponerContenido = () => {
    if (this.props.loading) {
      return <Spinner />;
    }
    if (this.props.error) {
      return <Fatal mensaje={this.props.error} />;
    }
    return <Tabla />;
  };

  render() {
    return (
      <div>
        <h1>Usuarios</h1>
        {this.ponerContenido()}
      </div>
    );
  }
}

const mapStateToProps = reducers => {
  return reducers.usuariosReducer;
};

const mapDispatchToProps = {
  getUsers
};

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

// Publicaciones/index.js

import React, { Component } from "react";
import { connect } from "react-redux";

import { getUsers } from "../../actions/usuariosActions";
import { getPublications } from "../../actions/publicacionesActions";

// const { traerTodos: usuariosTraerTodos } = usuariosActions;
// const { traerTodos: publicacionesTraerTodos } = publicacionesActions;

class Publicaciones extends Component {
  componentDidMount() {
    if (!this.props.usuariosReducer.usuarios.length) {
      this.props.getUsers();
    }
  }

  render() {
    console.log(this.props);
    return (
      <div>
        <h1>Publicaciones de ...</h1>
        {this.props.match.params.key}
      </div>
    );
  }
}

const mapStateToProps = ({ usuariosReducer, publicacionesReducer }) => {
  return {
    usuariosReducer,
    publicacionesReducer
  };
};

const mapDispatchToProps = {
  getUsers,
  getPublications
};

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

Leí algunos comentarios sobre lo confuso que puede llegar a ser trabajar asi pero creo olvidamos que muchas veces estamos trabajando en un equipo de desarrollo y quiza no tenemos el control total para escribir el codigo de forma que pudieramos evitar desde “raiz” este tipo de problemas. Esta es una solucion practica cuando nos encontramos en esta situacion. Muy buena clase.

clase #30: creo que me estoy perdiendo en el código.

pues muy interesante la des-estructuración de los metodos, pero seria mejor llamarlos a cada uno segun su función y de los datos que trae. una opinion.

no es una mala practica el cambiarle de nombre a las funciones para usarlo en una pequeña parte del código?, luego te sera casi imposible ubicarla cuando tengas un código mucho mas extenso, es mejor directamente cambiarle el nombre a la función.

Me parecio algo confuso tener los mismos nombres en los reucer. Es mejor desde el inicio definir types, actions y reducers unicos para evitar de raiz esos errores.


//publicacionesReducer.js
 case TRAER_PUBLICACIONES:
            return {
                ...state,
                publicaciones: action.payload,
                cargando: false,
            }

//usuariosReducer.js
 case TRAER_USUARIOS:
            return {...state, 
                usuarios: action.payload,
                cargando: false,                    
            }

Aunque entiendo a la mayoria de los que dicen que la clase fue una perdida de tiempo, pienso que para las personas que no tienen mucha experiencia en el lenguaje, pueden ver como solucionar problemas que quiza ellos mismos causen, sea cual sea la solución, lo importante es saber el como solucionarlos y que brinda javascript para hacerlo, como al desestructurar y renombrar, estoy seguro que si no fuese colocado el nombre del caso “traer_todos” tanto en un reducer como en el otro, muchos no fuesen aprendido que Redux trabaja de esta forma y qué responderian ambos reducers, para mi si vale la pena que mucha gente vea esta clase.

todos estos errores los puedes evitar creando tus propios nombres para las funciones, de hecho es una buena práctica al aprender, según me han comentado ayuda a crear tus propias soluciones a los problemas del programar, además si surgen errores es divertido arreglarlos 🤷‍♂️

  1. Cambiamos el nombre de los actions creators y nos llegan estos actions creators por props. Ya podemos llamar a los actions creator | this.props.usuariosTraerTodos() y los entregamos en el mapDispatchToProps

  2. Y cambiamos el nombre de los types en los reducers y actions creators. Por que cuando ocurra un dispatch este le consulta a todos los reducers, quien tiene ese caso y en los dos reducers se llamaban iguales.

  3. Hasta ahora no hemos usado el actions creator de publicaciones (es decir no llamamos este actions desde el componente publicaciones)

Vaya manera de complicarse la vida -.- xD

En el curso de React Hooks, en un post, explicaron que con useSelector y useDIspatch, puedes traer el estado, y disparar actions!
Obviamente usandolos en comoponentes funciones, aquí como quedaría:

import React, { useEffect } from 'react'
import {useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';
import { trearTodos } from '../../actions/publicacionesActions';

const Publicaciones = () => {
    const { key } = useParams();
    const dispatch = useDispatch()
    const {usuarios} = useSelector(state => state.user)
    useEffect(() => {
        dispatch(trearTodos());
       
    }, [dispatch]);
    return (
        <div>
            {key}
        </div>
    )
}

export default Publicaciones

Estoy perdido desde hace 3 clases 😦

Siento que para solucionar se repite codigo y tambien data, para ser sinceros no me gustó este metodo

Documentación de la destructuración en JS destructuracion DMZ

No me funciono con el destructuring asi que le cambie el nombre a los export de los actions y me va bien ahora.

Creó que es importante que nos muestre alternativas de como se debería de resolver posibles problemas a presentar en el proyecto, pero en mi caso pienso que es mucho más fácil crear los propios nombre para cada Reducer y dispatch, get_Publications o get_Users

Hay varias posibles soluciones como lo mencionan unos companeros en los aportes y creo que deberian de mostrarse en los cursos.

Aunque la opinión de muchos es que esta clase fue una perdida de tiempo, yo no lo veo asi por que recuerden que estamos viendo redux desde cero y que ademas es importante saber que hacer en todos los casos aunque ya con nuestros conocimientos podamos intuir una respuesta mejor o mas efectiva, aunque también seria interesante ver

Comparto el código de todo Publications esta clase:
·
View:

// src/components/Publications/index.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { withRouter } from "react-router";
import * as usersActions from '../../actions/components/usersActions';
import * as publicationsActions from '../../actions/components/publicationsActions';

const { getUsers: getAllUsers} = usersActions;
const { getPublications: getAllPublications} = publicationsActions;
class Publications extends Component {
  
  componentDidMount() {
    if (!this.props.usersReducer.users.length) {
      this.props.getAllUsers();
    }
    if (!this.props.publicationsReducer.publications.length) {
      this.props.getAllPublications();
    }
  }
  
  render() {
    console.log(`this.props`, this.props)
    return (
      <div className="margin-2rem">
        <h2>Publicaciones de: </h2>
        {this.props.match.params.key}
      </div>
    )
  }
}

const mapStateToProps = ({ usersReducer, publicationsReducer}) => {
  return {
    usersReducer,
    publicationsReducer
  };
};

const mapDispatchToProps = {
  getAllUsers,
  getAllPublications,
};

export default connect(mapStateToProps, mapDispatchToProps)(withRouter(Publications));

·
Reducer:

// src/reducers/components/publicationsReducer.js

import { GET_PUBLICATIONS, LOADING, ERROR } from '../../types/publicationsTypes';

const INITIAL_STATE = {
  publications: [],
  loading: false,
  error: ''
};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case GET_PUBLICATIONS:
      return {
        ...state,
        publications: action.payload,
        loading: false,
      }
    
    case LOADING:
      return {
        ...state,
        loading: true
      }

    case ERROR:
      return {
        ...state,
        loading: false,
        error: action.payload
      }  

    default: return state;
  };
};

·
Action:

// src/actions/components/publicationsActions.js

import axios from "axios";
import { GET_PUBLICATIONS, LOADING, ERROR } from '../../types/publicationsTypes';

const API_URL = 'https://jsonplaceholder.typicode.com/posts';

export const getPublications = () => {
  return async (dispatch) => {
    dispatch({
      type: LOADING
    })

    try {
      const response = await axios.get(API_URL);

      dispatch({
        type: GET_PUBLICATIONS,
        payload: response.data,
      });
    }
    catch (error) {
      new Error(console.error('Error occured: ',error.message));

      dispatch({
        type: ERROR,
        payload: `There's something went wrong: ${error.message}`,
        loading: false
      })
    }
  };
};

·
Types:

// src/types/publicationsTypes.js

export const GET_PUBLICATIONS = 'get_all_publications';
export const LOADING = 'loading';
export const ERROR = 'error';

Esta clase realmente no es confusa, acá en cambio hay que resaltar algunas cosas:

  1. El profesor no lo ha dicho, pero hasta el momento, la forma de desarrollo es lo que se llama Test Driven Development ─ es una metodología de desarrollo que consiste en realizar pruebas primero, evaluando el fallo, y a partir del fallo, se corrige. Nuestro profesor JuanDC hizo una entrada de Blog hablando de qué es TDD.
  2. Debemos entender que el profesor nos expone situaciones que sí pasan. Por el contrario de las situaciones donde crees que todo te lo van a entregar completo, con lineamientos e indicaciones… eso realmente pasa muuy poco.
  3. Redux exige un modelo mental en donde los datos fluyen por la interfaz de forma unidireccional. En esta clase el profesor replicó el mismo componente de Usuarios con Reducers, Actions y Types.
    Lo que hizo diferente es que en una sola vista está haciedo la conexión de publicaciones y usuarios sin que se colapse todo.

Recuerden siempre este mapa de Redux. no lo olviden, todo será más entendible si nos migramos al modelo Flux (de donde viene Redux)

Es mejor tener todo identificado de manera distinta, aunque te ahorra trabajo, pero si te equivocas a veces no es tan fácil ponerse a revisar carpeta por carpeta.

Hay varias posibles soluciones como lo mencionan unos companeros.

Excelente clase. Voy aprendiendo desde cero estos temas y espero seguir mejorando poco a poco. 🙂

Siempre esta super dividir las logicas y aprender a combinar acciones anotadisimo!

No seria mejor utilizar el id del usuario para buscar su propia informacion que ir a buscar todos los usuarios y tambien para encontrar los post unicamente buscarlos ?

 

Dejare la forma en el cual lo he hecho :

 

//Publicaciones
index.js
 

import React, { Component } from 'react'
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import * as usuariosActions from '../actions/usuariosAction';
import './index.css'

class Publicaciones extends Component {
    static propTypes = {
        match: PropTypes.object
    }

    componentDidMount() {
        const id = this.props.match.params.id;

        this.props.traerUsuarioPorId(id);
        this.props.traerPostPorUsuarioID(id);
    }

    render() {
        if (this.props.loading) {
            return <div>Loading...</div>
        }

        if (this.props.error) {
            return <div>Error</div>
        }

        return (
            <div>
                <h1 style={{ marginBottom: 55 }}>Publicaciones de {this.props.usuario.name}</h1>

                {this.props.post.map(({ title, body }, posicion) => (
                    <div key={posicion}>
                        <h2>{title}</h2>
                        <p>{body}</p>
                    </div>
                ))}
            </div>
        )
    }
}

const EstadosAPropiedades = ({ UsuarioReducer: { usuarios, error, loading, usuario, post } }) => {
    return {
        usuarios,
        error,
        loading,
        usuario,
        post
    };
};


export default connect(EstadosAPropiedades, usuariosActions)(Publicaciones);

 
 
//Actions Usuario

import { notification } from 'antd';```

&nbsp;

export const traerUsuarioPorId = (id) => async (dispatch) => {

dispatch({
    type: LOADING
})

notification.info({
    message: 'Cargando informacion',
    description: 'Pronto podras ver quien hizo las publicaciones',
    duration: 1
})


try {

    const request = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
    const respuesta = await request.json();

    dispatch({
        type: TRAER_USUARIO_POR_ID,
        payload: respuesta
    })
} catch (error) {
    dispatch({
        type: ERROR,
        payload: error.message
    })
}

};

export const traerPostPorUsuarioID = (id) => async (dispatch) => {

dispatch({
    type: LOADING
})

try {

    const request = await fetch(`https://jsonplaceholder.typicode.com/users/${id}/posts`);
    const respuesta = await request.json();

    notification.success({
        message: 'Exitoso!',
        description: 'Ahora podras ver toda la informacion de la publicacion',
        duration: 1.5
    })

    dispatch({
        type: TRAER_POST_POR_USUARIO_ID,
        payload: respuesta
    })
} catch (error) {
    dispatch({
        type: ERROR,
        payload: error.message
    })
}

}```
 
 
Por si quieren los types
 

export const TRAER_USUARIOS = 'TRAER_USUARIOS';
export const ERROR = 'ERROR';
export const LOADING = 'LOADING';
export const TRAER_USUARIO_POR_ID = "TRAER_USUARIO_POR_ID";
export const TRAER_POST_POR_USUARIO_ID = "TRAER_POST_POR_USUARIO_ID";```

Hola Devs:
-Para los que deseen una solucion mas limpia con los actions, reducers y los componentes, pueden checar mi repositorio: Click Aqui
Espero y les ayude.
Recuerden, #NuncaParesDeAprender 💚

Una pregunta, en el caso de que estemos usando Redux, suplanta en cierto sentido a los state de react?