No tienes acceso a esta clase

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

Curso de React Router 5 y Redux

Curso de React Router 5 y Redux

Oscar Barajas Tavares

Oscar Barajas Tavares

Debuggeando nuestro proyecto (agregando validaciones a nuestro componente card)

15/29
Recursos

Aportes 56

Preguntas 2

Ordenar por:

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

o inicia sesi贸n.

Si quieres evitar que el mismo elemento se agregue muchas veces a la lista de favoritos:

reducers/index.js

    case 'SET_FAVORITE':
      const exist = state.mylist.find(item => item.id === action.payload.id)
      if (exist) return {...state}

      return {
        ...state,
        mylist: [...state.mylist, action.payload]
      }

Hay otro bug y es que una vez se agrega una pel铆cula a la lista de mis favoritos ya no debe existir la opci贸n de a帽adirla nuevamente.

Recordemos que JS nos permite modificar los estilos de los elementos HTML
Para solucionar este bug agregue unas lineas en el m茅todo handleSetFavorite y **handleDeleteFavorite **, los cuales ahora remover谩n y agregaran el display de none, respectivamente.

  const { id, cover, title, year, contentRating, duration, isList } = props;
  const handleSetFavorite = () => {
    props.setFavorite({ id, cover, title, year, contentRating, duration });
    document.getElementById(id).style.display = 'none';
  };
  const handleDeleteFavorite = (itemId) => {
    props.deleteFavorite(itemId);
    document.getElementById(id).style.display = 'inline';
  };

Adicionalmente, debemos agregar el atributo ID en cada imagen (plus and delete icon):

          {isList ? (
            <img
              className='carousel-item__details--img'
              src={removeIcon}
              alt='Remove Icon'
              onClick={() => handleDeleteFavorite(id)}
            />
          ) :
            (
              <img
                className='carousel-item__details--img'
                src={plusIcon}
                alt='Plus Icon'
                onClick={handleSetFavorite}
                id={id}
              />
            )}

Otro bug que tambi茅n hay (no s茅 si lo corrijan despu茅s) es que puedes agreagar el mismo video varias veces al myList, y se muestra varias veces.

La propia consola te manda un error que el key se repite

Para resolver el bug de ya no volver agregar el mismo item lo resolv铆 as铆.

Existe otro bug, un item a帽adido actualmente a la lista, no puede volver a a帽adirse

He visto varias soluciones para el bug de 鈥渁gregar una pelicula m谩s de una vez a la lista de favoritas鈥.

Esta es mi propuesta.
Busco el 铆ndice (findIndex) del item que se va a agregar dentro de la lista myList.
Si el 铆ndice no existe (-1) agrego el payload, sino, regreso el state original,

case 'SET_FAVORITE':
            const index = state.myList.findIndex(items => items.id == action.payload.id);
            if(index == -1)
                return {
                    ...state,
                    myList: [...state.myList, action.payload]
                }
            return state;

Si jugaron un poco con las cartas del video, habr谩n visto que puedes agregar dos veces el mismo favorito. Para solucionarlo, hice esto.
Declar茅 una constante fuera del switch, que se encargar谩 de saber si existe o no, y coloqu茅 la condicion en el return.

const exists = state.mylist.find((item) => item.id === action.payload.id);

Y el return de ** SET_FAVORITE ** es

return exists ? state : {
        ...state,
        mylist: [...state.mylist, action.payload],
      };

Yo resolv铆 as铆 el bug de no a帽adir m谩s de una vez el mismo elemento

 case 'SET_FAVORITE':

      return state.myList.some((items) => items.id === action.payload.id) ? { ...state } :
        {
          ...state,
          myList: [...state.myList, action.payload],
        };

Me parece que para la validaci贸n de si el elemento existe quedar铆a m谩s simple de esta forma

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

Yo modifiqu茅 el reducer SET_FAVORITE.

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

Para evitar agregar el mismo elemento varias veces a la lista de favoritos se puede usar en reducer/index.js, lo siguiente:

Este Profesor sin duda est谩 entre los mejores de Platzi, no lo dejen ir y que por favor haga mas cursos

Se sigue a帽adiendo infinitamente desde trends. Para arreglarlo en src/reducer/index.js

const exists = state.myList.find((item) => item.id === action.payload.id);
      exists;

      return exists
        ? { ...state }
        : {
            ...state,
            myList: [...state.myList, action.payload],
          };```

Yo lo hice as铆:

case 'SET_FAVORITE':
      return state.mylist.find(item => item.id === action.payload.id)
        ? state
        : {
            ...state,
            mylist: [...state.mylist, action.payload],
          };

Existe un "bug " , porque no necesariamente se puede ver as铆 y es que si a帽ades un elemento a los favoritos , no deber铆a mostrarse en la lista de trends o de originals . Lo resoli as铆 :

import {
    actions
} from "../actions/index";

const reducer = (state, action) => {
 
    switch (action.type) {
        case actions.setFavorite:

            if (state.trends.find(items => items.id === action.payload.id)) {
                return {
                    ...state,
                    trends: state.trends.filter(items => items.id !== action.payload.id),
                    mylist: [...state.mylist, action.payload],
                }
            } else {
                return {
                    ...state,
                    originals: state.originals.filter(items => items.id !== action.payload.id),
                    mylist: [...state.mylist, action.payload],
                }
            }

            case actions.deleteFavorite:
                return {
                    ...state,
                    mylist: state.mylist.filter(items => items.id !== action.payload),
                        trends: [...state.trends, action.payload]
                }
                    default:
                        return state;
    }

};

export default reducer;

Para solucionar el bug que permit铆a agregar el mismo item varias veces a 鈥楳i lista鈥, he creado estas dos funciones en el Home.jsx justo antes del return del componente, una para trends y otra para originals, lo que hacen es comparar con myList y sacar los elementos repetidos

const trendsWhitOutMyList = trends.filter(
    ({ id: id1 }) => !myList.some(({ id: id2 }) => id2 === id1),
  );
  const originalsWhitOutMyList = originals.filter(
    ({ id: id1 }) => !myList.some(({ id: id2 }) => id2 === id1),
  );

Ademas hay que cambiar los map

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

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

Esta es otra forma de evitar que dos elementos se agreguen a la lista dos veces

if(check[0] !== undefined ){
              let band 
              band = false
                for(  let i = 0; i < Object.keys(check).length  ; i++){
                        console.log (check[i].id , action.payload.id)
                        if(check[i].id === action.payload.id){
                     
                         band = true
                     }
                    if(band === true){
                            return state
                        }
                    band = false
                }  
            }

Creo que es buena opci贸n hacerlo ya que elimina la redundancia de agregarlo si ya estaba agregado, pero el usuario sigue siendo capaz de agregarlo desde la lista de tendencias

case "SET_FAVORITE":
      const alreadyExists = state.myList.filter(
        (i) => i.id === action.payload.id
      );
      if (alreadyExists.length > 0) {
        return state;
      } else {
        return {
          ...state,
          myList: [...state.myList, action.payload],
        };
      }

      break;

Yo si hab铆a visto ese bug y lo correg铆 de la siguiente forma

const reducer = (state, action) => {
    switch (action.type) {
        case "SET_FAVORITE":
            return {
                ...state,
                myList: [...state.myList.filter(item => item.id !== action.payload.id), action.payload]
            }

Pero claro, segu铆a mostrando el bot贸n de agregar a favoritos, es mejor la soluci贸n del profe xD

Falto validar esto:

La clase anterior vi el bug que se resolvi贸 en esta clase y para mi sorpresa lo resolvieron en esta clase. Espero que m谩s adelante se resuelva el bug que pongo en la foto鈥 aun as铆 lo reparar茅 a mi modo igual que en la clase pasada cuando no sab铆a que se iba a arreglar el bug de esta clase

En nuestra aplicacion podemos presentar de forma infinita distintos elementos, esto no debe de ser asi. Por eso vamos a crear una validacion que nos permite identificar que estamos en la lista de agregados y quitar el boton de agregar.

Primero le agregaremos un nuevo valor , que preguntara que si esta en la lista, esto solo lo haremos a las tarjetas que invocamos directamente a MyList entonces quedaria asi nuestro elemento al usar el MAP:

{mylist.map((item) => <CarouselItem key={item.id} {...item} isList/>)}

Asi el valor se pasara como Trrue, entonces en nuestro ITEM solo tenemos que verificar si este valor es false o true. Esto con un valor ternario

{isList
        ?<img className="carousel-item__details--img" src={deleteicon} alt="Delete Icon" onClick={() => handleDeleteFavorite(id)} />
        :<img className="carousel-item__details--img" src={plusicon} alt="Plus Icon" onClick={handleSetFavorite} /> 
        }

Y ya quedaria listo.

Esta es mi soluci贸n al problema de que el mismo elemento se pueda agregar a favoritos muchas veces:


function CarouselItem(props) {
  const { item, myList } = props;
  const { setFavorite, removeFavorite } = props;
  const inFavorites = myList.find((el) => el === item);
  const handleFavorite = () => {
    if (inFavorites) {
      removeFavorite(item.id);
    } else {
      setFavorite(item);
    }
  };
  return (
    <div className="carousel-item">
      <img className="carousel-item__img" src={item.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={inFavorites ? removeIcon : plusIcon}
            alt="Plus Icon"
            onClick={handleFavorite}
          />
        </div>
        <p className="carousel-item__details--title">{item.title}</p>
        <p className="carousel-item__details--subtitle">
          {item.year} {item.contentRating} {item.duration} minutos
        </p>
      </div>
    </div>
  );
}
const mapDispatchToProps = {
  setFavorite: setFavorite,
  removeFavorite: removeFavorite,
};
const mapStateToProps = (state) => {
  return {myList: state.myList}
};

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



Otro enfoque, y que a m铆 me parece mejor, es separar este c贸digo en una funci贸n independiente, por ejemplo mainActionButton, la cual se encarga de validar el boton a mostrar y devolver el resultado.


  const mainActionButton = () => {
    if (isFavorite) {
      return <img className='carousel-item__details--img' src={removeIcon} alt='Trash Icon' onClick={handleDeleteFavorite} />;
    }

    return <img className='carousel-item__details--img' src={plusIcon} alt='Plus Icon' onClick={handleAddFavorite} />;
  };

  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' />
          {mainActionButton()}
        </div>
        <p className='carousel-item__details--title'>{title}</p>
        <p className='carousel-item__details--subtitle'>
          {`${year} ${contentRating} ${duration}`}
        </p>
      </div>
    </div>
  );

escribi esta peque帽a validacion para cambiar el simbolo de agregar a la lista por el de borrar tanto en la lista como en el original, myList lo tomo del store.Pero me parece algo ineficiente.

const isInMyList = () => props.myList.some(item => item.id === id);
{isInMyList()?
                <img 
                    className="carousel-item__details--img" 
                    src={removeIcon} 
                    alt="Minus Icon"
                    onClick={()=>handleDeleteFavorite(id)}
                />
                :<img 
                    className="carousel-item__details--img" 
                    src={plusIcon} 
                    alt="Plus Icon"
                    onClick={handleSetFavorite}
                />}

Brutal, jajaja no me di cuenta del bug jaja

Para eliminar el item que se a帽ade a favoritos de las otras listas:

case "SET_FAVORITE":
      return state.mylist.find(item => item.id === action.payload.id)
        ? state
        : {
            ...state,
            mylist: [...state.mylist, action.payload],
            trends: state.trends.filter(item => item.id !== action.payload.id),
            originals: state.originals.filter(item => item.id !== action.payload.id),
          };

Que buena clase para validar los componentes, vamos por mas!

Para que se cambie el bot贸n de a帽adir por el de borrar en los elementos que est谩n en favoritos en la lista de trends:

        <Carousel>
          {trends.map(item => {
            let isList = false;
            if (myList.length > 0)
              isList = myList.reduce(favourite => favourite.id !== item.id);

            return <CarouselItem key={item.id} {...item} isList={isList} />;
          })}
        </Carousel>

Para originals ser铆a exactamente igual solo que hay que mapear el array originals.

aun asi tenemos otro Bug y es que podemos a帽adir varias veces el mismo elementos desde tendencias o originales a myList

estupendo ufff, que lindo es aprender, igual mi cabeza exploto ajajajja

con esto y la bandera para que en myList no salga el icono de add evitamos agregar el mismo elemento mas de una vez

case 'SET_FAVORITE':
            
            return {
                ...state,
                myList: [
                    ...state.myList,
                    ...state.myList.map(i=>i.id).indexOf(action.payload.id)===-1?[action.payload]:[]
                ]
            }

isList, es mas que una simple variable, puedes colocare, pollito, siexiste, mesirve, etc, 鈥 es solo un identificador del 鈥渋tem鈥 si existe, ya despu茅s vamos a CarouselItems.jsx, para validar 鈥渋sList鈥 si existe o no 馃槃

Justo en la clase pasado coment茅 como hab铆a resuelto este bug, y me alegra saber que fue muy parecido al del profesor. Me lo puse como reto antes de llegar a esta clase porque creo que as铆 se demuestra lo que se est谩 aprendiendo !! 馃槃

Sigue siendo posible a帽adir un item infinitamente desde el carrousel de tendencias u originales. Adem谩s los items que estan en myList no pueden ser eliminados desde otros carrousels

XD Ya hab铆a resuelto este problema en el video de la clase pasada! Se que hay distintas formas de resolver un problema, sin embargo mi soluci贸n fue exactamente la misma que la del profe! 馃槃

Si como a m铆 no te sali贸 el icono, s贸lo tienes que especificar que isList es true expl铆citamente en el componente de Home, de esta forma:

isList={true}

no estoy seguro qu茅 es payload 馃

Les comparto mi fragmento de validaci贸n:

{
            isList ?
              (
                <img
                  className='carousel-item__details--img'
                  src={removeIcon}
                  alt='Remove Icon'
                  onClick={() => handleDeleteFavorite(id)}
                />
              ) :
              (
                <img
                  className='carousel-item__details--img'
                  src={plusIcon}
                  alt='Plus Icon'
                  onClick={handleSetFavorite}
                />
              )
          }

Mi implemenacion para evitar que se agreguen repetidos, me di cuenta que si en el 鈥渆lse鈥 no regresaba el 鈥溾tate鈥 todo se rompia

		case 'SET_FAVORITE':
			if ( state.mylist.filter((items) => items.id === action.payload.id).length === 0) {
				return {
					...state,
					mylist: [...state.mylist, action.payload],
				};
			} else {
				return {
					...state,
				};
			}```

Hola, alguien me puede explicar en que momento es isList se vuelve falso (teniendo en cuenta que su estado inicial es true)? para saber que ya no debe mostrar el bot贸n de agregar sino el de borrar?

That鈥檚 how I stay!!






.

Hab铆a notado el bug y yo lo corregi de la siguiente manera:

const reducer = (state, action) => {
    switch (action.type) {
        case 'SET_FAVORITE':
            return {
                ...state,
                myList: (!state.myList.some(item => item.id === action.payload.id)) ? [...state.myList, action.payload] : state.myList
            }
        case 'DELETE_FAVORITE':
            return {
                ...state,
                myList: state.myList.filter(item => {
                    return item.id !== action.payload
                })
            }
        default:
            return state;
    }
};

export default reducer;

Yo le agregu茅 una validaci贸n para que no se repitan los elementos de myList y adem谩s que muestre una alerta sencilla que diga que el elemento ya se encuentra a帽adido en myList:

En mi caso tuve que hacer una condicion adicional en el Home para realizar esta condici贸n:
馃槂

nameList.map((category) => (
          categories[category].length > 0 && (
            <Categories key={category} title={category}>
              <Carousel>
                {categories[category].map((video) => (
                  (category === 'myList') ?
                    (<Item key={video.id} {...video} isFavorite />) :
                    (<Item key={video.id} {...video} />)
                ))}
              </Carousel>
            </Categories>
          )
        ))

Para poner un 铆cono diferente cuando el elemento est谩 en mi lista, podemos utilizar redux, solo necesitamos a帽adir una propiedad extra en nuestro initialState, y en los reducers trabajarla:

Yo lo hice asi

        <div>
          <img src={Play} alt='Play' />
          { !isList && <img src={Plus} alt='Plus' onClick={handleSetFavorite} />}

          { isList && <img src={Delete} alt='Delete' onClick={() => handleDeleteFavorite(id)} />}

        </div>

Yo lo hab铆a resuelto de esta forma. En vez del atributo isList, le puse favorite. Luego valid茅 si era favorite mostrar谩 uno u otro bot贸n e implementar谩 una u otra l贸gica.

<img
            className="carousel-item__details--img"
            src={favorite ? minusIcon : plusIcon}
            alt="Plus Icon"
            onClick={favorite ? handleRemoveFavorite : handleSetFavorite}
          />

Algo tranquilo despu茅s de un tren de informaci贸n.

No me gust贸 la 鈥渧alidaci贸n鈥 que hicieron en esta clase.
Lo que yo hice fue pasarle a CarouselItem dos nuevos props: showPlusIcon y showRemoveIcon.
showRemoveIcon se lo paso nada m谩s a los CarouselItems de 鈥淢i lista鈥, y dependiendo si es true o false, muestro el removeIcon o no.
showPlusIcon se lo paso nada m谩s a los elementos de las otras listas, desde Home.jsx, y el valor es true si el item no est谩 en myList y false en caso contrario, de esta manera:

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

Y as铆 queda la validaci贸n en CarouselItem:

{showPlusIcon &&
                        <img 
                            className="carousel-item__details--img"
                            src={plusIcon}
                            alt="Plus Icon"
                            onClick={handleSetFavorite}
                        />
                    }
                    {showRemoveIcon &&
                        <img 
                            className="carousel-item__details--img"
                            src={removeIcon}
                            alt="Remove Icon"
                            onClick={handleRemoveFavorite}
                        />
                    }

s

Super!

Pr谩ctica:

Para arreglar el bug, implemente el siguiente codigo
if (state.myList.filter((item) => payload.id === item.id).length > 0) {
return { 鈥tate };
}
return { 鈥tate, myList: [鈥tate.myList, payload] };