Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Creando los reducers

13/29
Recursos

Un action de Redux va a contener dos elementos:

  • type: para indicar la acción que se va a ejecutar.
  • payload: es la información que estamos mandando al reducer.

Dentro de los reducers usaremos un switch para separar la lógica por cada tipo de acción que tendremos en Redux.

Aportes 83

Preguntas 34

Ordenar por:

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

😦
Me tomó mucho tiempo entender Redux, tuve que volver a reproducir las clases y buscar en internet sobre arreglos y objectos porque no tenía ni idea de porque a veces destructurabas o por qué, y tampoco tenía idea de cómo funcionaban los datos y el estado pero ya por fin entendí.

Tercera vez que miro este video y contando…

Después de repetir las clases, este es mi resumen:

  1. El Storage es como una base de datos de los estados

  2. El connect permite la conexión entre el componente con el Storage y tiene 2 parámetros. Ejemplo - Connect (Primero,Segundo):

    Primero: Envía el estado actual del Storage al componente para que sea utilizado por medio de su props. Para lograrlo, se crea una función que indicará que atributos se quieren utilizar en el componente y luego las asigna a su props.
    Segundo: Envía al Reduce la acción que hemos encapsulado y que, por alguna razón que aún no entiendo, al ser llamada por el import en el componente se le atribuye su props. Cuando esta acción llega al Reduce, es identificada mediante el Switch por su atributo Type para su ejecución. Luego, el Reduce envía el resultado al Storage para su actualización.
    Importante: El Reduce también tiene 2 atributos “(state, action)”:

    • state: Es el estado que el Stage envía al Reduce. Por lo tanto, es el estado que se va a actualizar.
    • action: Es la acción encapsulada que fue enviada por el componente al Reduce para que se actualice el estado del Stage.

Espero haberme dejado entender y que a alguien más se sirva para que siga aprendiendo sin muchas dudas en las siguientes clases.

Mencionar que si les surge un error de que cada item deberia tener una key, es porque no lo estamos mandando en el payload de setFavorite en CarouselItem, con esto lo pueden solucionar:

` const {id, cover, title, year, contentRating, duration } = props

const handleSetFavorite = () => {
    props.setFavorite({
        id,
        cover,
        title,
        year,
        contentRating,
        duration
    })
}

`

solo es de recibir y enviar el id

Con este video entendí como funciona todo, no es necesario hagan el ejercicio yo solo mire los primeros 30 min y fue suficiente para entender como funcionaba todo
Click para ir al video

Espero les sirva de algo

Para elementos repetidos dentro del array, yo hice lo siguiente , modifiqué el reducer para filtrar si existe ese elemento dentro del state.myList.

 case 'SET_FAVORITE':
      if (state.myList.filter((element) => element.id == action.payload.id).length !== 0) {
        return state;
      }
      return {
        ...state,
        myList: [...state.myList, action.payload],
      };

Les comparto para evitar que se agregue un item duplicado al array mylist (Esta es mi manera de hacerlo tal vez haya alguna mejor por favor comentarla si es así.)

const { id, cover, title, year, contentRating, duration, setFavorite, mylist } = props
    
const handleSetFavorite = () =>{
        const exist = mylist.find(item => item.id == id)
        if(exist){
            alert("Ya tienes agregado a favorito");  
        }else{
            setFavorite({
                id,
                cover, 
                title, 
                year, 
                contentRating, 
                duration
            })
        }
    }

recuerden agregar el mapStateToProps para acceder a mylist

const mapStateToProps = (state) => {
    return {
        mylist : state.mylist
    }
}


export default connect(mapStateToProps, mapDispatchToProps)(CarouselItem)

<h1>intento mio de entender el proceso de redux</h1>
<h3>Creando reducers en React</h3>

En esta ocasión vamos a guardar los favoritos que agreguemos con el boton de añadir a favoritos de nuestra interfaz. Para ello comenzamos creando y exportando la función setFavorite de nuestro archivo de actions:

export const setFavorite = payload =>({ // Retornamos y exportamos la función un objeto
	type: 'SET_FAVORITE', // Este es el nombre/descripción que le vamos a dar a nuestro action
	payload // El payload se le podría llamar como la acción de la UI
})

Con esto ya tendriamos nuestro archivo de actions listo, ahora debemos ir a nuestro ir a nuestro reducers para manejar la información que recibimos.

La función de Reducer recibe dos parametros que son el state y el action. Con eso claro vamos a hacer una validación con switch para añadir elementos a la myList cuando el action sea el de SET_FAVORITE:

NOTA: Recordar que los parametros de state y action los conseguimos mas adelante cuando hagamos el connect con nuestra función setFavorite.

const reducer = (state, action) =>{
	switch(action.type){ // Vamos a validar el type que habimaos mencionado que es como la descripción del action
		case 'SET_FAVORITE'
		return{
			...state, // Desestructuramos la variable state
			myList = [...state.myList, action.payload] // Asignamos nuevos valores a mylist que fueron los que se trajeron del action. Si no desestructuramos la myList se sobrescribiran y no se añadiran nuevos favoritos
		}
		default // Caso por defecto si no cumple el action con ninguno
		return state
	}
}

Ya con estos dos archivos listos nos dirigimos al componente donde tengamos nuestro videoItem

Lo primero que debemos hacer es importar connect y exportar nuevamente pero con la función de connect:

import {connect} from 'react-redux'

...

export default connect(null, mapDispatchToProps)(videoItem) // El primer parametro va null porque no vamos a solicitar props sino vamos a enviarlos

Ahora debemos definir nuestro mapDispatchToProps con nuestro action a enviar*😗

const mapDispatchToProps = {
	setFavorite
}

Para hacer esto también hay que importar setFavorite de actions:

import {setFavorite} from '../actions'

Ya con esto tendriamos que definir nuestra función manejadora que se llamaría handleSetFavorite y la creamos dentro de nuestro componente:

let videoItem = props => {
	let { img, title, etc} = props
	let handleSetFavorite = () => {
		props.setFavorite({img, title, etc})
	}
}

Se me hizo interesante el ‘Snake case’, no sabía que tenía un nombre, sólo conocía el Camel Case.

Para quien le interese, hay más tipos de case:

  • camelCase

Raw: user login count
Camel Case: userLoginCount

  • PascalCase

Raw: user login count
Pascal Case: UserLoginCount

  • snake_case

Raw: user login count
Snake Case: user_login_count
Snake Case (All Caps): USER_LOGIN_COUNT

  • kebab-case

Raw: user login count
Kebab Case: user-login-count

Artículo completo.

Todo bien. Solo me sale un warning:
“backend.js:6 Warning: Each child in a list should have a unique “key” prop.”

Me pasé un día completo sin entender un bug, y era solamente que en un archivo había puesto

mylist

y lo correcto era

myList 

🤣

En mi caso como modifiqué el json no podía hacerlo funcionar directamente de la forma que está en el vídeo. Por lo que tuve que hacer algo que se usa en el curso de Redux con Bedu. que fue mapear mis array de listas, entonces que cuando encontrará a “Mi lista”, hiciera push del payload a mi array llamado “videos” que contiene la lista.

Si alguien hizo algo similar a lo que yo hice con el JSON y tiene problemas en esta parte, les dejo mi código del reducer 😃

case 'SET_FAVORITE':
            
            const newLists = state.lists.map(list => {
                let value = {...list}
                if(list.title === "Mi lista"){
                    list.videos.push(action.payload)
                }
                return value
            })

            return {
                ...state,
                lists: newLists
            }

Las Actions describen que algo pasó, pero no especifican cómo cambió el estado de la aplicación en respuesta. Esto es trabajo de los reducers.

Que diferencia, ahora si entiendo como interactua cada elemento de nuestro componente, para solicitar la ejecución de una acción hacia nuestro store. La carga util es el dato que modifica el estado de la app.

Buenas Prácticas:
Muchas cosas no están estandarizadas en Redux, por lo que brinda flexibilidad para personalizar las cosas, pero como la mayoría de nosotros no queremos una solución personalizada para cada pequeño detalle cotidiano, la comunidad tiende a establecer lo que se conoce como “buenas prácticas”.

Para separar este tipo de datos de los datos normales, se utiliza la propiedad conocida como “payload”. Ahora, sobre qué podemos pasar po “payload” y qué debería estar en el mismo nivel es discutible, pero un estándar popular (recomendado por los documentos oficiales) es “Flux Standard Action” la Acción estándar de flujo que establece que entre los requisitos oficiales puede agregar un “payload” , un “error” o un “metapropierty”.

**POR TANTO:
**Cualquier información sobre la acción que no sea el “type” o “estado de la acción” debe ser parte del campo de “payload”.

A mi me salio el error que decia cada item deberia tener un Key unico.

Esto pasa porque no estamos recibiendo un key en cada CarouselItem, y por lo tanto tampoco estamos enviando un key a myList, entonces ahi es donde nos salta el error.

Adicionalmente, en mi codigo, yo encontre que a lllamar la lista de CarouselItems, no le estaba pasando ningun key ni ningun prop a los CarouselItems de myList en Home, por lo que los items en myList salian con todas sus propiedades undefined .

Todo ésto lo podemos solucionar, siguiendo estos pasos:

  1. Asegurarnos de que estamos enviandole un ID (Key unico) y todas las props que necesitamos a cada CarouselItem que llamamos en myList en Home:
<Categories title='My lists'>
          <Carousel>
            {myList.map((item) => (
              <CarouselItem key={item.id} {...item} />
            ))}
          </Carousel>
</Categories>
  1. Verificar que estamos recibiendo un ID (Key unico) para cada CarouselItem y que estemos definiendo un proptype para ID (Key unico) en la declaracion de CarouselItem (src/components/CarouselItem.jsx):
const CarouselItem = (props) => {
  const { id, cover, title, year, contentRating, duration } = props;
CarouselItem.propTypes = {
  id: propTypes.number,
  cover: propTypes.string,
  title: propTypes.string,
  year: propTypes.number,
  contentRating: propTypes.string,
  duration: propTypes.number,
};
  1. Verificar que estemos enviando un ID (Key unico) a nuestro store en la declaracion de CarouselItem (src/components/CarouselItem.jsx):
const handleSetFavorite = () => {
    props.setFavorite({
      id,
      cover,
      title,
      year,
      contentRating,
      duration,
    });
  };

Espero que a alguien le sirva 😅

Estuve muchísimo tiempo tratando de arreglar un bug y resultó que había escrito myList.lenght en vez de **myList.length **

olv está chingón el reducer uwu

En lo personal me costo mucho entender redux. y les traigo una forma diferente de implementarlo pero igualmente efectiva…

  1. En el src creamos una carpeta llamada redux y dentro creamos dos carpetas una llamada reducers y otra store, cada una con su respectivo index.js

  2. En el index de la carpeta redux/store colocamos nuestro initialState de la siguiente forma:

const initialState = {
  userActive: {
	name :"Campeon"
	},
  token: false,
};
export default initialState;

  1. bien, ahora en el index de la carpeta redux/reducers colocamos las acciones que queremos hacer sodre la data del store, como: traer, eliminar, agregar.
const reducer = (state, action) => {
  switch (action.type) {
    case "SET_VALIDATE": {
      return { ...state, token: action.payload };
    }
    case "SET_USER_ACTIVE": {
      return { ...state, userActive: action.payload };
    }
    default: {
      return state;
    }
  }
};
export default reducer;

  1. Bueno ahora lo que hay que hacer es envolver nuestra aplicacion con nuestro store, esto con el fin de que podamos acceder a la data del store desde cualquier componente.
    Entonces vamos a nuestro index.js principal donde tenemos nuestro ReactDOM.render y agregamos lo siguiente:
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import reducer from "./redux/reducers";
import initialState from "./redux/store";
import App from "./routes/app";

const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__();
const store = createStore(reducer, initialState, composeEnhancers);

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById("root")
);

  1. Ya estamos muy cerca, ahora solo tenemos que ir al componente que queremos utilizar la data y traerla con un hook llamado useSelector desde reactr-redux y lo mostramos donde convengamos.
import { useSelector, useDispatch } from "react-redux";
const Header = () => {
  const userActive = useSelector((state) => state.userActive);

  return (
    <div className="HeaderContainer">
        <strong>{userActive.name && userActive.name}</strong>
</div>
  1. y listo, asi de facil, ahora solo nos queda utilizar las acciones que habiamos creado en la carpeta redux/reducers para esto utilizamos un hook llamado useDispatch desde react-redux de la siguiente manera
import { useDispatch } from "react-redux";
const Header = () => {
  const dispatch = useDispatch();;

  return (
    <div className="HeaderContainer">
        <button
          onClick={() => {
            dispatch({
              type: "SET_USER_ACTIVE",
              payload: {},
            });
          }}
        >
         Salir
        </button>
    </div>
  );
};

export default Header;

Te explico como funciona el dispatch: simplemente es una funcion que necesita un objeto con dos datos, el type y el payload. el type es el nombre que utilizamos en el CASE del reducer y el payload es la nueva data.

Ahora te invito a usar useSelector en otro componente diferente y ver si efectivamente la data se modifica.

Bueno eso es todo por ahora, en lo personal esta forma me parece mucho mas sencilla de entender y de implementar. si tienen problemas o dudas me dejan su comentario. Corazon para que no quede en el olvido.

Personalmente este curso no me esta gustando, he regresado varias veces las clases pero no logro entender si quiera que es un reducer y en que me beneficia usar redux, alguien mas se siente asi? o le pasa lo mismo?

Así se vería el Home con el uso del Hooks useSelector de react-redux

import React from 'react';
import { useSelector } from 'react-redux';
import Search from '../components/Search';
import Categories from '../components/Categories';
import Carousel from '../components/Carousel';
import CarouselItem from '../components/CarouselItem';

import '../assets/styles/App.scss';

const Home = () => {
  const { myList, trends, originals } = useSelector(state => state);
  return (
    <>
      <Search />
      {myList.length > 0 && (
        <Categories title="Mi Lista">
          <Carousel>
            {myList.map(item => 
              <CarouselItem key={item.id} {...item} />
            )} 
          </Carousel>
        </Categories>
      )}

      <Categories title="Tendencias">
        <Carousel>
          {trends.map(item => 
            <CarouselItem key={item.id} {...item} />
          )} 
        </Carousel>
      </Categories>

      <Categories title="Originales de Platzi Video">
        <Carousel>
          {originals.map(item => 
            <CarouselItem key={item.id} {...item} />
          )} 
        </Carousel>
      </Categories>

    </>
  );
};

export default Home;

y en CarouselItem podemos hacer uso del Hooks useDispatch, quedando de la siguiente manera:

import React from 'react';
import { useDispatch} from 'react-redux';
import PropTypes from 'prop-types';
import { setFavorite } from '../actions';
import '../assets/styles/components/CarouselItem.scss';
import playIcon from '../assets/static/play-icon.png';
import plusIcon from '../assets/static/plus-icon.png'

const CarouselItem = (props) => {
  const { id, cover, title, year, contentRating, duration } = props;
  const dispatch = useDispatch();

  const handleSetFavorite = () => {
    const payload = { id, cover, title, year, contentRating, duration }
    dispatch(setFavorite(payload))
  }

  return (
    <div className="carousel-item">
      <img className="carousel-item__img" src={cover} alt={title} />
      <div className="carousel-item__details">
        <div>
          <img className="carousel-item__details--img" src={playIcon} alt="Play Icon" />
          <img 
            className="carousel-item__details--img" 
            src={plusIcon}
            alt="Plus Icon"
            onClick={handleSetFavorite}
          />
        </div>
        <p className="carousel-item__details--title">{title}</p>
        <p className="carousel-item__details--subtitle">{`${year} ${contentRating} ${duration}`}</p>
      </div>
    </div>
  )
};

CarouselItem.propTypes = {
  title: PropTypes.string,
  year: PropTypes.number,
  contentRating: PropTypes.string,
  duration: PropTypes.number,
  cover: PropTypes.string,
};

export default CarouselItem;

Algo que acabo de notar, es que si recargan el navegador la lista pierde la información

Dejo este enlace de video que me ayudo a comprender un poco mejor el funcionamiento de REDUX.
https://www.youtube.com/watch?v=5iMhFH9alI0

Este tema hay que tomarlo con pinzas y lupa de relojero 🔍

Fue toda una odisea este tema de redux, como todos al principio pasé este curso solamente confiando ciegamente en el profesor y sin saber lo que estaba haciendo. Se me hizo tan difícil de entender que simplemente lo dejé de lado.

A mi parecer en toda esta escuela de JS abordaron demasiado rápido y un poco superficial estos temas de los hooks, router y redux. A mi gusto explican todo demasiado rápido que hasta se me lagguea el cerebro tratando de encontrar una explicación lógica y no simplemente verlo todo como “magia”.

Mi recomendación es que no se frustren en tratar de entenderlo a la primera, en vez de eso vayan a buscar como se trabaja con el state de cada componente por separado. Practiquen mucho simplemente con el state y el useState (aún no sé como usar useEffect) y ya después se van a dar cuenta que van a necesitar si o sí una forma de manejar una sola información para toda su aplicación en vez de estar repitiendo los datos en cada componente. Es ahí cuando vuelven a repasar estas clases y ahora todo va a tener sentido.

También lo que he visto mucho en estos cursos es que trabajan demasiado los componentes como funciones o arrow functions y no tanto como clases. Yo me rehusaba a usarlos, pero la verdad me siento más cómodo ahora que los empleo todos como clases y no simples funciones (claro hay veces que es innecesario, pero en su mayoría todo lo manejo con clases).

De igual manera esta es mi opinión meramente personal, nunca he sido bueno para aplicar y relacionar las cosas con la simple teoría. Siempre he sido más de estar a prueba y error, eventualmente termino entendiendo todo y aunque sienta que voy demasiado lento eventualmente todos llegamos a donde mismo.

P.D: Una cosa que me ayudó bastante también es haber empezado a usar React Bootstrap, ya que aquí los componentes interactivos como modals, navbar y formularios se manejan mucho con la manipulación de los estados.

Para el error de two childrens duplicados, la solucion en el Home, basta con agregar un segundo argumento en .map, no se olviden de encerrar ambos argumentos entre parentesis:

return (
    <>
      <Search />
      {myList.length > 0 &&
        <Categories title="Mi Lista">
          <Carousel>
            {myList.map((item, id) =>
              <CarouselItem key={id} {...item} />
            )}
          </Carousel>
        </Categories>
      }
      <Categories title="Tendencias">
        <Carousel>
          {trends.map((item, id) =>
            <CarouselItem key={id} {...item} />
          )}
        </Carousel>
      </Categories>
      <Categories title="Originales de Platzi Video">
        <Carousel>
          {originals.map((item, id) =>
            <CarouselItem key={id} {...item} />
          )}
        </Carousel>
      </Categories>
    </>
  );```


Tomado de stackOverflow: https://stackoverflow.com/questions/52219852/two-children-with-the-same-key-in-react

Me costo mucho hacer la destructuración del objeto ya que mis listas están dentro de un objeto categories, pero al fin lo conseguí :3

me queda algo así:

case 'SET_FAVORITE':
      return {
        ...state,
        categories: {
          ...state.categories,
          myList: [...state.categories.myList, action.payLoad],
        },
      };

Es de esta forma entonces que se pueden actualizar datos dentro de atributos de un objeto 😃

Una forma para evitar que agregue duplicados podría ser

case 'SET_FAVORITE':
            const result = state.myList.filter(item => item.id === action.payload.id);
            return result.length > 0 ? state : {
                ...state,
                myList: [...state.myList, action.payload]
            }

En el reducer en vez de usar un switch no es mejor usar un “if else” son solo dos casos…

Tengo un problema, escribo todo el codigo bien, pero no me agrega los CarouselItems a la seccion de myList, no me arroja ningun error ni nada, simplemente no funciona, tengo el codigo exactamente igual que el profesor en la clase, he revisado muy bien el codigo pero no encuentro el motivo de por que no funciona, por favor si alguien me puede ayudar, se lo agradeceria

Se debe validar que el carrusel que envía la acción no sea el de myList (o repetiremos elementos en nuestra lista), para esto podemos agregar un prop al CarouselItem, digamos usable y setearlo por defecto en true, luego en el handleFavorite usamos una condicional, de la siguiente manera:

CarouselItem.js:

...
const CarouselItem = ({
  usable = true,
  id,
  cover,
  title,
  year,
  contentRating,
  duration,
  setFavorite
}) => {
  const handleSetFavorite = () => {
    if (usable) setFavorite({ id, cover, title, year, contentRating, duration })
  }
...

Home:

...
<Carousel>
  {myList.map(item => (
    <CarouselItem key={item.id} {...item} usable={false} />
  ))}
</Carousel>
...

Shift + Alt + F ordena el código y ahorra muuucho tiempo

Configuración de Carousel Item

Creación del archivo reducer

Para manejar el flujo de informacion de la aplicacion, vamos a trabajar los Actions y los reducers. En este caso en el de agregar a la lista. vamos a ver los actions que en nuestro index vamos a crear el primer funcion que vamos a escribir la accion que vamos a hacer y pasar un objeto que tendremos disponible dentro del reducer, el cual va a tomar la accion que estamos realizando para guardar la accion en el estado.

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

Ahora el reducer se va a encargar de entender que es lo que esta pasando y como actualizara el estado. Crearemos un switch que nos permite recibir el type, evaluarlo con un caso y saber que haremos con el estado.

const reducer = (state, action) => {
    
    switch (action.type) {
        case 'SET_FAVORITE':
            return {
                ...state,
                mylist: [...state.mylist, action.payload]    
            }
            break;
    
        default:
            return state;
    }

}
export default reducer;

Ahora solo actualizaremos nuestro componente de Carousel Item que ya sabemos que tenemos que conectar nuestra aplicaicon. Aqui vamos a mandarle nulo ya uqe no vamos a mapear los estados, el otro es MapDispatchToProps. Otra cosa es agregar la constante de mapDispatchToProps a la cual le daremos la funcion de setFavorite y lo importamos de los actions:

const mapDispatchToProps = {
  setFavorite, 
}

export default connect(null, mapDispatchToProps)(CarouselItem)

Ahora modificaremos nuestro componente para que tenga un retorno explicito para poder agregarle logica. Ahora mandaremos los props de forma deconstruida.

const { cover, title, year, contentRating, duration } = props;

Ahora crearemos nuestra funcion que hara la parte de agregar los elementos, a la cual solo le diremos que en props.setFavorite mandarle el objeto con los valores de nuestro ITEM para que lo agregue a mi lista

const handleSetFavorite = () => {
    props.setFavorite({
      cover, title, year, contentRating, duration,
    })
  }

recomiendo usar useDispatch y useSelector en vez de connect

Por si alguien tiene algun error con el render de su Lista

        {myList.length > 0 &&
            <Categories title="Mi lista">
                <Carousel>
                    {
                        myList.map(item =>
                            <CarouselItem key={item.id} {...item} />
                        )
                    }
                </Carousel>
        </Categories>
        }

Permiso me gustaría aclarar que Favorito en inglés se escribe, Favourite y se pronuncia algo así cómo (leer literal en español)= FEIVRIT … 😁

Más de una hora mirando el por qué no me agregaba los valores a la lista de mylist y era por que en el objeto de mapStateToProps del container Home tenías state.myList y en el data estaba como “mylist”

Yo desconozco donde emplear la lógica para realizar validaciones, pero desde mi punto de vista los componentes no deberían tener dicha lógica, por lo que hice la validación de no agregar duplicados en el reducer:

case 'SET_FAVORITE':
      if (state.myList.some((item) => item.id === action.payload.id)) {
        return {
          ...state,
        };
      }
      return {
        ...state,
        myList: [...state.myList, action.payload],
      };

Wow, me vi el curso de react hooks, y viendo como funciona el useReducer (que me costo infiernos entenderlo), ahora entiendo más fácil redux, y si ustedes aun no lo logran, no se rindan, todo el mundo lo sabría si fuera tan fácil como una suma !

Recomiendo este par de videos para entender mejor Redux:

video1
Video2

Yo antes de aprender redux hice aplicaciones simples pero bien elaboradas usando bases de datos reales, y eso me ayudo en realidad a comprender el flujo completo, me parece que es mejor saber un poco de backend para poder implementar redux de una forma mas clara.

Tengo una duda y espero que me puedan ayudar, entiendo que se crea una función en el CarouselItem.jsx, dicha función trae el action y le pasa como parámetro (payload) los props que trae el item, al mismo tiempo el reducer mediante el switch selecciona el type y hace alguna cosa, en este caso mantener el state, y los items que ya tenga el array myList, para agregar lo que payload traiga (si me estoy equivocando en algo, díganme porfa :v), lo que no entiendo, es cómo demonios es que se agrega el componente completo si sólo le estamos pasando props. Quizá sea muy absurda o muy evidente la respuesta, pero no logro comprender !!, mil gracias !

Hoy con ayuda de los hooks en React, creo que puede ser más fácil su compresión.

Dejo aquí esto para que les sirvan de ayuda:

https://react-redux.js.org/api/hooks

Un action de Redux va a contener dos elementos:

type: para indicar la acción que se va a ejecutar.
payload: es la información que estamos mandando al reducer.

Dentro de los reducers usaremos un switch para separar la lógica por cada tipo de acción que tendremos en Redux.

Realmente se aprende de los errores.

Al finalizar la tarea nada me funcionaba y me toco investigar más a fondo para entender que estaba haciendo mal, al final tenia un **return {} ** donde debía estar un return () , pero aprendí mucho de redux en el proceso.

Gracias benditos Bugs… jejjeje

Explicación del método connect

duda, redux guarda el estado en el localStorage??

y cuando le introdujimos alguna informacion a payload?

no me agrega al pulsar el boton me sale un error!

porque le el swith no se utiliza el breack?

Por favor alguien podria explicarme bien la desestructuracion "…"
Entiendo su funcion de traer todos los elementos del state a un bloque de codigo , pero hasta ahi nomas no lo entiendo en profundidad!

Desde ya muchas gracias!!

me sirve cuando agrego pero me sale el siguiente error,

porque no se uso el hook useSelector? o es que a la salida de este curso el hook no existia?

No me dejaba guardar más de un elemento, encontre dando console.log en el reducer, que no llevaba el ID. Asi que por si les pasa los mismo, deberían agregarlo a las props del carouselItem.

const CarouselItem = (props) => {
  const { id, cover, title, year, contentRating, duration } = props

  const handleSetFavorite = () => {
    props.setFavorite({
      id, cover, title, year, contentRating, duration,
    })
  }
  return (
    <div className='carousel-item'>
      <img className='carousel-item__img' src={cover} alt='' />
      <div className='carousel-item__details'>
        <div>
          <img
            className='carousel-item__details--img'
            src={playIcon}
            alt='Play Icon'
          />
          <img
            className='carousel-item__details--img'
            src={plusIcon}
            alt='Plus Icon'
            onClick={handleSetFavorite}
          />
        </div>
        <p className='carousel-item__details--title'>{title}</p>
        <p className='carousel-item__details--subtitle'>
          {`${year} ${contentRating} ${duration}`}
        </p>
      </div>
    </div>
  )
}

¿De donde sale action.type?

Encontre esta lista de reproduccion en youtube para el que le sirva para entender mejor los conceptos de redux https://www.youtube.com/watch?v=5iMhFH9alI0&list=PL4WxketMZHyeeU3pilSJbgiIFnVzSUFVb&ab_channel=JuanJoseOrtiz

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

Me da este error, segui todos los pasos

Vaya ando un poco confundido no lo voy a negar, leyendo los comentarios y los links que dan de apoyo los compañeros comprendo un poco mas, pero creo que debo practicar bastante para lograr entender a profuncidad bien esto de Redux

Creo que el término no es “destructurar el estado”, porque eso hace referencia a la extracción de los datos de este mismo, sino más bien “esparcir”, pues al fin y al cabo lo está haciendo con el “spread operator”, ú “operador de esparcimiento” definido por los tres puntos “…”.
Sé que esto no hará que la aplicación funcione diferente, pero a nivel de conceptos se me hace que tiene más sentido así.

De acuerdo a la documentación de airbnb, resulta mejor hacer el destructuring de los datos como lo teníamos anteriormente, y no sacando las variables desde los props que se reciben.

si hubiera entendido Redux de hace años de esta manera, gracias por este gran curso

Acá les comparto un diagrama de Redux, para ayudar a comprender un poco más la explicación del profesor.

Como dato curioso por si alguien más se lo preguntó en el minuto 1:40 cuando configura el type del action y dice que lo haremos con snake case, se refiere a una práctica al asignar valores en el cual se separan las palabras con Under Score (_) en vez de espacio Ej: SNAKE_CASE

Esta clase estuvo genial! Cada vez amo más a React ❤️

Alguna idea de por qué me aparece este error:

Esto es lo que tengo en Home.js:

import React from 'react';
import { connect } from 'react-redux';
import Search from '../components/Search';
import Categories from '../components/Categories';
import Carousel from '../components/Carousel';
import CarouselItem from '../components/CarouselItem';
import '../assets/css/App.scss';

const Home = ({ myList, trends, originals }) => {
  return (
    <>
      <Search />
      {
        myList.length > 0 && (
          <Categories title='Mi Lista'>
            <Carousel>
              {
                myList.map((item) => (
                  <CarouselItem key={item.id} {...item} />
                ))
              }
            </Carousel>
          </Categories>
        )
      }
      <Categories title='Tendencias'>
        <Carousel>
          {
            trends.map((item) => (
              <CarouselItem key={item.id} {...item} />
            ))
          }
        </Carousel>
      </Categories>
      <Categories title='Originales'>
        <Carousel>
          {
            originals.map((item) => (
              <CarouselItem key={item.id} {...item} />
            ))
          }
        </Carousel>
      </Categories>

    </>
  );
};

const mapStateToProps = state => {
  return {
    myList: state.myList,
    trends: state.trends,
    originals: state.originals,
  };
};

export default connect(mapStateToProps, null)(Home);

En la vista CarouselItem hay un pequeño bug y es que no envía un id en setFavorite por lo que en el Home se esta creando items con key undefined para solucionar el warning solo es pasar el id del props al setFavorite

const CarouselItem = ({ id, cover, title, year, contentRating, duration, setFavorite }) => {
  const handleSetFavorite = () => {
    setFavorite({
      id, cover, title, year, contentRating, duration
    });
  }
  return (
    <div className="carousel-item">
      <img className="carousel-item__img" src={cover} alt={title} />
      <div className="carousel-item__details">
        <div>
          <img className="carousel-item__details--img" src={playIcon} alt="Play Icon" />
          <img className="carousel-item__details--img" src={plusIcon} alt="Plus Icon" onClick={handleSetFavorite} />
        </div>
        <p className="carousel-item__details--title">{title}</p>
        <p className="carousel-item__details--subtitle">
          {`${year} ${contentRating} ${duration}`}
        </p>
      </div>
    </div>
  );
};```

Cuando se usa mapStateToProps & mapDispatchToProps ?

parece magia esto, xD

Dos dias revisando el código y tenia mal escrito SET_FAVORITE
XD

Alguien sabe porque ocurre este error, es al momento de hacer click en el icono de plus

Tío yo sí había pensado, esa función en actions está muy raraaaaa

El action le pasa al reducer una acción que debe ejecutar y un payload, y el reducer es el encargado de saber como va a modificar (o no) el estado en función de la acción y el payload entregados por el reducer.
En la doc. dice

“puedes pensar en un action como un evento que describe algo que sucede en la aplicación”

Y dice de un reducer
"Puedes pensar en un reducer ccomo un event listener el cual maneja los eventos con base en el action que recibe(evento) type (y el payload)

b

Este esquema (aproximado), muestra las partes dentro de cada compoente para recordar estos import o funciones importantes

Práctica:

Se puede usar el shorcut para formatear el codigo alt+shit+f