No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Reg铆strate

Comienza en:

5D
3H
44M
27S
Curso de React Router 5 y Redux

Curso de React Router 5 y Redux

Oscar Barajas Tavares

Oscar Barajas Tavares

Finalizando reducers y eliminar favoritos

14/29
Recursos

Aportes 48

Preguntas 12

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

En lo personal no recomiendo pasar el nombre de las acciones como texto plano, es muy posible crear typos.

Deber铆an utilizar un objeto intermediario que maneje cada acci贸n, en mi caso queda algo as铆:
Actions

Reducers

Recomendaci贸n: Ulilizar constantes en Redux.
Es recomendable usar constantes en redux, por ejemplo, crear un archivo que se llame 鈥渁ctionTypes.js鈥, y dentro colocar lo siguiente:

export const SET_FAVORITE = 'SET_FAVORITE'
export const DELETE_FAVORITE = 'DELETE_FAVORITE'

Estas constantes las importaremos en los actions y en los reducers.

驴Con qu茅 fin se usan estas constantes? Muchos no le encuentran sentido porque el valor tiene el mismo nombre que la constante, pero los beneficios son los siguientes.

  • Ayuda a mantener una consistencia y evita los errores al escribir c贸digo, ya que si escribes Strings en las actions y en los reducers puede que en una de esas veces te equivoques.
  • Algunas veces el usuario desea ver qu茅 actions existen antes de trabajar en alguna. Si trabajas en un equipo puede que alguien la haya implementado. Tener todas las actions como constantes en un archivo te facilitar谩 esa b煤squeda.
  • La lista de_ action types_ que fueron a帽adidas, eliminadas o actualizadas en un _Pull Request _ayuda a todo el equipo a visualizar r谩pidamente qu茅 cambios se est谩n haciendo en la funcionalidad.
  • Si cometes un error (typo) cuando importas tus constantes, obtendr谩s undefined cuando intentes ejecutar tu c贸digo. Es m谩s f谩cil encontrar este error de variable que intentando descifrar por qu茅 no pasa nada cuando ejecutas tu action.

Espero que les haya servido de algo. No es algo que yo me haya inventado, muchos manejan esa escructura. Si gustan, aqu铆 les dejo m谩s informaci贸n:

Ha sido doloroso pero reconfortante saber que he entendido. Por favor corrijanme lo que sea necesario. Es complejo entender el patr贸n de dise帽o de Flux, pues todo es archivos separados, pero tomando el tiempo de entender todo es legible. Les dejo mi comprensi贸n, espero les aydue a qui茅nes no la logran de primera:
.

  1. Se alimenta la aplicaci贸n por medio del Provider cuando definimos el createStore(reducer, initialState). 脡sto le enviar谩 informaci贸n al componente que necesite acceder al Store.
// index.js
const initialStore = { /* ... */ }

const store = createStore(reducer, initialState);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('app'),
);

1.1. El reducer va a recibir el estado inicial que se pasa en createStore , pero tambi茅n, en su funci贸n recibir谩 la acci贸n que debe hacer cuando ocurra un llamado al Store.
.
2. Dentro del reducer vamos a devolver el estado actualizado del Store 煤nicamente cuando ocurra una acci贸n, cuando se despache una acci贸n . Dependiendo de la acci贸n el estado del store se actualiza o se queda igual, sea agregar a favorito o crear un estado inicial al ingresar a Home, respectivamente por ejemplo.

2.1. El payload es lo que vamos a enviarle a la acci贸n, que recibir谩 el reducer, para actualizar el Store o actualizar el estado.

// actions.js
export const setFavorite = (payload) => ({
  type: 'SET_FAVORITE',
  payload,
});

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

2.2. Cuando el reducer recibe ese payload por medio del action, podemos hacer algo con la informaci贸, en este caso, se actualiza la lista myList

// reducer.js
const reducer = (state, action) => {
  switch (action.type) {
    case 'SET_FAVORITE':
      console.log('action -> ', action);
      return {
        ...state,
        myList: [
          ...state.myList.filter((item) => item.id !== action.payload.id),
          action.payload,
        ],
      };

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

    default:
      return state;
  }
};

export default reducer;

.
3. Al tener definida la estructura del Store, del reducer y de las acciones, podemos definir funciones para manejar estas acciones directamente en el UI --> Renderizamos la informaci贸n en componente Home:
3.1. Conectamos Home al Store por medio de connect():

// Home.jsx
export default connect(mapStateToProps, null)(Home);

3.2. Definimos la informaci贸n que debe traer Home desde el store, es por eso que se define mapStateToProps , pues ser谩 el argumento que trae del estado de Store la informaci贸n que necesita el componente, y pasa como PROPIEDADES al mismo componente:

// Home.jsx
const mapStateToProps = (state) => {
  return {
    myList: state.myList,
    trends: state.trends,
    originals: state.originals,
  };
};

3.3. Se pasan las propiedades a Home:

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

      <Categories title='Originals'>
        <Carousel>
          {originals?.map((item) => {
            return (
              <CarouselItem key={item.id} {...item} />
            );
          })}
        </Carousel>
      </Categories>

      <Categories title='Trends'>
        <Carousel>
          {trends?.map((item) => {
            return (
              <CarouselItem key={item.id} {...item} />
            );
          })}
        </Carousel>
      </Categories>

    </>
  );
};
  1. Estas propiedades las recibe el componente CarouselItem y ser谩n las que pinten una pel铆cula. sea en la lista de Trends u Originals. 4.1. Para que reciba props, se debe conectar el componente al Store:
// CarouselItem
const mapDispatchToProps = {
  setFavorite,
  deleteFavorite,
};

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

4.2. El objeto mapDispatchToProps trae las ACCIONES. Se realiza puesto que en cada CarouselItem vamos a ejecutar una acci贸n que modificar谩 el Store -> Estas acciones tambi茅n se podr谩n llamar por medio de los PROPS del componente. Logrando que podamos definir los manejadores de estas acciones:

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

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

  const handleDeleteFavorite = () => {
    props.deleteFavorite(id);
  };

  return (
    !id ? (
      <>
        <p>La lista est谩 vac铆a</p>
      </>
    ) :
      (
        <>
          <div className='Carousel--item'>
            <img className='Carousel--item__img' src={cover} alt={title} />
            <div className='Carousel--item__details'>
              <p className='Carousel--item__details--title'>{title}</p>
              <p className='Carousel--item__details--subtitle'>
                {`${year} | ${contentRating} | ${duration}`}
              </p>
              <div className='Carousel--item__details--buttons'>
                <img src={playIcon} alt='Play' />
                <img src={plusIcon} alt='Plus' onClick={handleSetFavorite} />
                <img src={removeIcon} alt='Delete' onClick={handleDeleteFavorite} />
              </div>
            </div>
          </div>
        </>
      )
  );
};

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

Renderizando cada uno de los items que existen en el Store.
.
5. El render inicial har谩 que existan listas de Trends y Originals, pero cada uno de los CarouselItem tendr谩 una acci贸n: setFavorite y deleteFavorite. Estas acciones manipulan el Store definiendo los estados para la lista de favoritos (myList).

El m茅todo filter() crea un nuevo array con todos los elementos que cumplan la condici贸n implementada por la funci贸n dada.

Una sugerencia para que no se agregue el mismo elemento varias veces a myList puede ser:

Yo escribi la funcion handleDeleteFavorite de la siguiente manera:

const handleDeleteFavorite = () => {
    props.deleteFavorite(id);
  };

Y en el onclick de remove quedo asi:

onClick={handleDeleteFavorite}

Ya que estamos descomponiendo el valor id de props, no veo la razon de crear una arrow function en el evento onclick para pasarle el valor del id.

al tomar est谩 carrera pude aprender que a cada momento podemos adquirir nuevos conocimientos鈥 me pude sorprender de lo que se puede hacer con javascript

Genial el uso de Redux, es complicado pero con la pr谩ctica todo se aprende

Pr谩ctica: my prefect code.

Estuve viendo el Curso de Redux por Bedu y no lo logre terminarlo por la cantidad de vacios que estaba teniendo con respecto a algunos componentes de Redux鈥 llevo estas pocas clases con el profesor Oscar y porfin logr茅 sintetizar de una manera muy facil y entendible (para mi) el uso de mapStateToProps y mapDispatchToProps
Respeto y admiraci贸n total por la forma tan f谩cil en la que ense帽a el profesor 鈽

Espero no ser el 煤nico que con cada clase que termino se me dibuja una sonrisa!! animo chicos y chicas dentro de poco vamos a crear cosas muy interesantes!!

Para los amantes de los iconos comparto

Good Class!!!




como podriamos hacer para que el remove-icon solo se muestre en myList y no en todas las secciones?

usando hooks

dispatch(deteleFavorite(itemId));```

Tip: Si quieren que los iconos cambien, por ejemplo que el de eliminar s贸lo aparezca en Mi lista: Lo pueden hacer con un ternario:

const hasListItem = hasItem != undefined 
     ? 
     <img src={iconDelete} alt="icono delete" onClick={() => handleDeleteFavorite(id) }/> 
     :
     <img src={iconPlus} alt="icono play" onClick={handleSetFavorite} />;```

Este es mi codigo para carouseItem para eliminar el plus de mylist y agregar en su lugar el remove

/* eslint-disable import/prefer-default-export */
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { setFavorite, deleteFavorite } from '../../redux/actions';
import '../../assets/styles/CarouselItem.scss';
import playIcon from '../../assets/static/play-icon.png';
import plusIcon from '../../assets/static/plus-icon.png';
import removeIcon from '../../assets/static/remove-icon.png';

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

  const handleSetFavorite = () => {
    props.setFavorite({
      id, cover, title, year, contentRating, duration, listType: 'myList',
    });
  };
  const handleDeleteFavorite = (itemId) => {
    props.deleteFavorite(itemId);
  };

  const button = (listType !== 'myList') ?

    <img className='carousel-item__details--img' src={plusIcon} alt='Plus Icon' onClick={handleSetFavorite} /> :
    <img className='carousel-item__details--img' src={removeIcon} alt='remove Icon' onClick={() => handleDeleteFavorite(id)} />;
  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' />
          { button }
        </div>
        <p className='carousel-item__details--title'>{title}</p>
        <p className='carousel-item__details--subtitle'>

          {`${year} ${contentRating} ${duration}`}

        </p>
      </div>
    </div>
  );

};

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

const mapDispatchToProps = {
  setFavorite,
  deleteFavorite,
};
export default connect(null, mapDispatchToProps)(CarouselItem);

super, viendo la case nuevamente, se entiende que bien

seg煤n yo el bug es que cuando el CarouselItem esta en 鈥淢i lista鈥 no deber铆a mostrarse el icono de agregar y cuando esta en las dem谩s secciones no deber铆a mostrarse el icono de eliminar

Echenle un ojo a esto: https://www.sololearn.com/
Ahi hay cursos de todo. El de 鈥淩eact + Redux鈥 me sirvio para esclarecer conceptos que estaban con alfiler. Saludos

Les recomiendo echar un vistado al paquete immutability-helper, ayuda much铆simo cuando tenemos objetos o arreglos con varios niveles de anidaci贸n, adem谩s se me hace mucho m谩s sencillo su c贸digo.

ya le voy entendiendo a lo de redux, creo que falta un poco mas de react en la ruta de javascript

Para no tener problema con los type es mejor crear un archivo donde podeamos tener mayor control de ellos

export const ADD_ITEM       = 'ADD_ITEM';
export const DELETE_ITEM = 'DELETE_ITEM';

luego usarlo en los action como en el reducer

export const setFavorite = payload => ({
    type: type.ADD_ITEM,
    payload
});
case type.ADD_ITEM:

El bug es que estamos agregando el icono a todos los items cuando solo lo debe de tener los de mylist

En esta ocasi贸n recomiendo crear un componente diferente para myList.
No necesitamos que este el bot贸n de agregar a mi lista y tampoco necesitamos y no queremos que en el resto de las listas este el bot贸n de borrar de la lista.
Creo que lo mejor seria crear un componente para myList igual al resto pero intercambiando el bot贸n de agregar a la lista por el de borrarlo.
D铆ganme si hay una mejor forma de solucionarlo.

La descripci贸n de los action puedes intentar dejarlo en un archivo Json, despu茅s lo que har铆as es importar este archivo Json en el archivo reducer y en el archivo de los action, as铆 solo el cambio depende de un archivo

creado el delete en actions

Buena clase!

no se elimina el item, tampoco me sale ningun error鈥

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

const CarouselItem = (props) => {
  const { id, cover, title, year, contentRating, duration } = props;
  const handleSetFavorite = () => {
    props.setFavorite({
       id, 
       cover,
       title, 
       year, 
       contentRating, 
       duration,
    })
  }
  const handleDeleteFavorite = itemId => {
    props.deleteFavorite(itemId);
  }
  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}
       />

       <img className="carousel-item__details--img" 

        src={removeIcon} 
        alt="Remove Icon"
        onClick={()=>handleDeleteFavorite(id)}
       
       />

    </div>
    <p className="carousel-item__details--title">{title}</p>
    <p className="carousel-item__details--subtitle">
      {`${year} ${contentRating} ${duration}`}
    </p>
  </div>
</div>
);
}

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

const mapDispatchToProps = {
  setFavorite,
  deleteFavorite,
};
export default connect(null, mapDispatchToProps)(CarouselItem);```

Habia puesto myList en un lado con l minuscula y no funcionaba, pero tampoco daba error xD

A mi me funciona enviando directamente el id a deleteFavorite, sin pasarlo por parametros ni nada, 驴es mala practica??

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

  const handleDeleteFavorite = () => {
    props.deleteFavorite(id);
  };

<img src={deleteIcon} onClick={handleDeleteFavorite} />```

Muy buena clase, y probando la aplicaci贸n detecte el bug jeje

exploto mi cabeza en esta clase ajjaja, changos tengo que verlo muchas veces

Se utiliza el m茅todo filter para crear un nuevo Array con todos los elementos que cumplan con la condici贸n implementada en la funci贸n

Todo correcto hasta el momento, me sirvi贸 de mucho el curso introductorio de JavaScript. Sin embargo, recuerdo con Leonidas que usaba una librer铆a para no mutar el estado de la aplicaci贸n y con ella todo perd铆o sentido porque manejaba muchos errores y segun yo estaba todo bien.

Tengo una consulta sobre el payload鈥
estube viendo que en otros casos SI se le pasa informacion al mismo
ej
payload{
date:12-12-11,
country: eeuu,
}
LO QUE NO ENTIENDO ES PORQUE PASAMOS EL PAYLOAD VACIO

hola comunidad, personalmente se me dificult贸 mucho entender e implementar el connect, por lo que googlenado encontre una formas mas practica para reemplazar connect, con UseDispatch y UseSelector https://levelup.gitconnected.com/react-redux-hooks-useselector-and-usedispatch-f7d8c7f75cdd

Que incre铆ble es entender esto, trat茅 de estudiar lo mismo en otro lado y no entend铆 como aqu铆, gracias Oscar de verdad.

Me encanto la parte de agregar id

Un poco confuso para mi pero no nos rendiremos!

Como se trabaja con imagenes wepb?

Tengo un problema para implementar la funcionalidad de eliminar favoritos, tengo un error en el m茅todo filter y no he logrado encontrarlo. Este es el link del repositiorio en github: https://github.com/wilmarFlorez/w-video

Hola! Yo lo dise帽茅 para que el bot贸n de eliminar de favoritos solo aparezca cuando el item esta en la lista de 鈥渕yList鈥

Toda la l贸gica la maneje desde el action de setFavorite, les muestro como lo hice:

export const setFavorite = favorite => (dispatch, getState) => {
  // Other way to update the list

  const { myList } = getState().videosReducer;

  const updatedList = [...myList, favorite];

  const updatedListItem = updatedList.map(item => ({
    ...item,
    favorite: !!(favorite.id),
  }));

  dispatch({
    type: SET_FAVORITE,
    payload: updatedListItem,
  });
};

Por que no funciona de esta manera?:

<img 
	className='carousel-item__details--img' 
	src={removeIcon} 
	alt='Remove Icon' 
	onClick={handleDeleteFavorite(id)} 
/>

Por se debe asignar la funci贸n handleDeleteFavorite(id), usando un arrow function?

<img 
	className='carousel-item__details--img' 
	src={removeIcon} 
	alt='Remove Icon' 
	onClick={() => handleDeleteFavorite(id)} 
/>

No entendi que es payload

usando Dispatch

const handleDeleteFavorite = () => {
    dispatch(deleteFavorite(id))
  };
onClick={handleDeleteFavorite}

Vamos a empezar a crear en ACTIONS y crear el que va a describir lo que vamos a hacer, en este caso lo uqe vamos a eliminar, quedaria igual que la anterior:

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

Ahora en nuestro reducer vamos a crear un nuevo caso del switch en el cual vamos a devolver en el return lo que vamos a trabajar para nuetro estado. Siempre vamos a trabajar con el estado que ya tenemos y manejamos mylist. Lo que haremos es crear en nuestra lista crear un nuevo array que cumplan una condicion dada con ayuda del metodo filter. Esto evaluando con el valor de ID.

case 'DELETE_FAVORITE':
            return{
                ...state,
                mylist: state.mylist.filter(items => items.id !== action.payload),
            }

Ahora tenemos que modificar nuestro CarouselItem, primero tenemos que importar la funcion de deletefavorite:

import { setFavorite, deleteFavorite } from '../actions';

Al igual que ir agregando el icono que se encargara de esto. Tambien tenemos que agregarlo a nuestro DispatchToProps

const mapDispatchToProps = {
  setFavorite, 
  deleteFavorite,
}

Ahora crearemos nuestra funcion handleDeleteFavorite ala cual le pasaremos de parametro el ID:

const handleDeleteFavorite = (itemId) => {
    props.deleteFavorite(itemId);
  }

Este ID lo tenemosq ue recibir de los props el cual lo habiamos ignorado, solo tenemos que agregarlo en todos lados donde destructuramos estos props:

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

Ahora para llamar la funcion pondremos en nuestra nueva imagen:

<img src={deleteicon} alt="Plus Icon" onClick={() => handleDeleteFavorite(id)} />

Esto lo llamamos de distinta forma ya que neceistamos agregar este ID que asignamos para poderlo identificar y eliminarlo de nuestro estado.