No tienes acceso a esta clase

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

Agregando Inmutabilidad a nuestra Pokedux

18/22
Recursos

Aportes 21

Preguntas 3

Ordenar por:

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

o inicia sesi贸n.

Por si a alguien le pasa como a mi que no puede instalar la dependencia, recuerden que es 鈥渋mmutable鈥 con doble 鈥渕鈥 y no 鈥渋nmutable鈥 馃槄

Creo que Mariang茅lica tiene un error de c贸digo, pero corr铆janme si me equivoco.
Yo NO vi el loader en su app y creo que tiene que ver con que ella puso el action.payload de SET_LOADING dentro del array.

Yo lo puse afuera:

case SET_LOADING:
			return state.setIn(['loading'], action.payload);

Y a m铆 s铆 me muestra el loading as铆.

En mi caso, por defecto se instal贸 鈥渋mmutable鈥: 鈥淾4.1.0鈥, a diferencia de la 4.0 de la clase, esto requiri贸 cambios en el reducer y en el App. js:

pokemon.js

switch (action.type) {
    case SET_POKEMONS:
	   // action.action.payload, porque uso un midleware q modifica el listado
      return setIn(state, ['pokemons'], fromJS(action.action.payload));
    case SET_LOADING:
      return setIn(state, ['loading'], action.payload);
    case SET_FAVORITE:
      const currentPokemonIndex = get(state, 'pokemons').findIndex(
        (pokemon) => pokemon.get('id') === action.payload.pokemonId
      );

      if (currentPokemonIndex < 0){
        return state;
      }

      const isFavorite = getIn(state, ['pokemons', currentPokemonIndex, 'favorite']);
      
      return setIn(state, ['pokemons', currentPokemonIndex, 'favorite'], !isFavorite);
    default:
      return state;
  } 

App.js

const pokemons = useSelector(state => get(state, 'pokemons')).toJS();
const loading = useSelector((state) => get(state, 'loading'));

Con la version 4.1.? de immutable quedar铆a de la siguiente forma

import { fromJS, setIn, getIn} from 'immutable';
...
case SET_POKEMONS:
      //return { ...state, pokemons: action.payload };
      //return state.setIn(['pokemons'], fromJS(action.payload))
      return setIn(state, ['pokemons'], fromJS(action.payload))

Me agrada la propuesta, pero prefiero que todo sea m谩s Vanilla. Ayuda a que seamos un poco mejores con el c贸digo y c贸mo nos va cuando manipulamos las cosas鈥 En este caso es una clase y se puede practicar, pero siento que cuando se tiene claro el uso de inmutabilidad por Vanilla JS, se puede lanzar con librer铆as y otros recursos.

Hice el c贸digo, pero la verdad me parece que es mucho mejor trabajar con js nativo, siento que tengo m谩s control y encima la librer铆a complica mucho m谩s lo que ya est谩 hecho, asi lo siento yo.

valida la informaci贸n , pero me parece m谩s complicado que el m茅todo nativo de js spread operator

npm install immutable 

Mi practica

Instalaci贸n de Immutable

npm i immutable

reducers/pokemons.js

import {SET_FAVORITE,SET_LOADING,SET_POKEMON} from "../actions/types.js";
import {fromJS, get, getIn, setIn} from "immutable";

const initialState = fromJS({
    pokemons: [],
    loading:false,
    favorites:[]
});

export const pokemonsReducer = (state,action) => {
    console.log(state)
    switch (action.type) {
        caseSET_POKEMON:
            //return {...state, pokemons: action.payload}
            return setIn(state,['pokemons'],fromJS(action.payload));
            break;
        caseSET_FAVORITE:
            const currentPokemonIndex = get(state,'pokemons').findIndex(
                (pokemon) => {
                    returnpokemon.get('id') ==action.payload.pokemonId;
                }
            );
            if (currentPokemonIndex < 0) {
                returnstate
}
            //const isFavorite = state.get('pokemons').get(currentPokemonIndex).get('favorite');
            const isFavorite = getIn(state,['pokemons',currentPokemonIndex,'favorite']);
            return setIn(state,['pokemons',currentPokemonIndex,'favorite'],!isFavorite);
            break;
        caseSET_LOADING:
            return setIn(state,['loading'],action.payload);
            break;
        default:
            return {...state};
            break;
    }
}

App.jsx

import {useEffect} from 'react'
import {useDispatch, useSelector} from "react-redux";
import {Col, Spin} from 'antd';
import Searcher from "./components/Searcher";
import PokemonList from "./components/PokemonList.jsx";
import {getPokemon} from "./api";
import {getPokemonWithDetails, setLoadings} from "./actions";
import Logo from "./assets/logo.svg";
import {get} from "immutable";
import './App.css'

function App() {
    const pokemons = useSelector(state => get(state,'pokemons'))?.toJS();
    const loading = useSelector(state => get(state,'loading'));
    const dispatch = useDispatch();
    useEffect(() => {
        const fetchPokemons = async () => {
            dispatch(setLoadings(true))
            const response = await getPokemon();
            dispatch(getPokemonWithDetails(response));
            dispatch(setLoadings(false))
        }
        fetchPokemons();
    }, []);

    return (
        <div className="App">
            <Col span={4} offset={10}>
                <img src={Logo} alt="pokeapi"/>
            </Col>
            <Col span={8} offset={8}>
                <Searcher/>
            </Col>
            {loading ? (
                <Col offset={12} className="Spinner">
                    <Spin spinning size="large"/>
                </Col>
            ) : (
                <PokemonList pokemons={pokemons}/>
            )}

        </div>
    )
}

export default App;

Recomiendo ampliamente el uso de la librer铆a **鈥渋mmer鈥 **en ves de el uso de 鈥渋mmutable鈥, puesto que es mucho m谩s facil de utilizar y no necesitas de m谩s complejidad que el c贸digo basico para el uso de redux, es decir, no necesitas metodos get o set u setIn,
Es muy facil de utilizar ya que solo necesitamos usar su m茅todo produce para que realice la inmutabilidad por su cuenta.
Documentaci贸n / gu铆a paso a paso del uso de immer:
https://immerjs.github.io/immer/

Para la siguiente clase y el uso de combineReducers, se necesita instalar 鈥渞edux-immer鈥. 脡sta es su gu铆a de implementaci贸n:
https://github.com/salvoravida/redux-immer

Dej茅 comentado el inicial por si acaso :v

   //--return { ...state, loading: action.payload };
      return state.setIn(["loading"], action.payload);

en reducers/pokemons.js

case SET_LOADING:
      // return {...state, loading: action.payload}
      return state.setIn(["loading"], fromJS(action.payload))

en app.js agregamos la siguiente l铆nea de c贸digo para loading

const loading = useSelector(state => state.get("loading"));

Despues de muchos intentos les paso lo que hice para que me ande, utilice mucha ayuda de los comentarios y google y me quedo asi

package.json
Me quede con esta version porque era la mas descargada en npm

    "immutable": "4.3.4", 

App.js

/* eslint-disable react-hooks/exhaustive-deps */

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Col, Spin } from 'antd'; 
import Searcher from './components/Searcher';
import PokemonList from './components/PokemonList';
import logo from './statics/logo.svg'
import { getPokemon } from './api';
import { getPokemonsWithDetails, setLoading } from './actions';
import './App.css';
import { get } from 'immutable'

function App() {

  const pokemons = useSelector(state => get(state, 'pokemons')).toJS()
  const loading = useSelector(state => get(state, 'loading'))
  const dispatch = useDispatch()

  useEffect(() => {
    const fetchPokemons = async() => {
      dispatch(setLoading(true))
      const pokemonsRes = await getPokemon()
      dispatch(getPokemonsWithDetails(pokemonsRes))
    }


    fetchPokemons()

  }, [])

  return (
    <div className="App">
      <Col span={4} offset={10}>
        <img src={logo} alt="Pokedux"/>
      </Col>
      <Col span={8} offset={8}>
        <Searcher/>
      </Col>
      {loading ? <Col offset={12}>
        <Spin spinning size="large"/>
      </Col> :  <PokemonList pokemons={pokemons}/> }
    </div>
  );
}


export default App

El reducer pokemons.hjs

import { fromJS, get, getIn, setIn } from 'immutable'
import { SET_FAVORITE, SET_LOADING, SET_POKEMONS } from "../actions/types"

const initialState = fromJS({
    pokemons: [],
    loading: false,
})

export const pokemonsReducer = (state=initialState, action) => {
    switch(action.type) {
        case SET_POKEMONS:
            return setIn(state, ['pokemons'], fromJS(action.payload))
        case SET_FAVORITE:
            const currentPokemonIndex = get(state,'pokemons')
                .findIndex((pokemon) => {
                    return get(pokemon, 'id') === action.payload.pokemonId
                } )

            if (currentPokemonIndex === -1) return state

            const isFavorite = getIn(state, ['pokemon', currentPokemonIndex, 'favorite'])
            
            return setIn(state, ['pokemosn', currentPokemonIndex, 'favorite'], !isFavorite)
        case SET_LOADING:
            return setIn(state, ['loading'], fromJS(action.payload))
        default:
            return state
    }
}
para el case en SET\_LOADING simplemente utilice la funcionalidad en SET\_POKEMONS, cambiando la propiedad "pokemons" por "loading". ![](https://static.platzi.com/media/user_upload/image-3f4f8fc6-5afe-4c87-8ddb-0db056859a86.jpg)

Curioso ver c贸mo la app funciona en los v铆deos pero misteriosamente el c贸digo no es el mismo que aparece en los ficheros del final鈥

Reto

Para resolver el reto hice lo siguiente

pokemons.js

App.jsx

Si les sale la advertencia

npm WARN @apideck/better-ajv-errors@0.3.6 requires a peer of ajv@>=8 but none is installed. You must install peer dependencies yourself.
npm WARN fork-ts-checker-webpack-plugin@6.5.2 requires a peer of typescript@>= 2.7 but none is installed. You must install peer dependencies yourself.
npm WARN tsutils@3.21.0 requires a peer of typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta but none is installed. You must install peer dependencies yourself.

al instalar immutable, no se preocupen. Para saltarsela solo deben agregar --save-dev al instalar.

Mi soluci贸n del lado de los reducers fue:

return state.setIn(['loading'], fromJS(action.payload))

Y del lado de App.js:

const loading = useSelector((state) => state.get('loading'));
case SET_LOADING:
      return state.set('loading', action.payload );

/****************/

const loading =  useSelector((state) => state.get('loading'));

Esta un poco diferente mi soluci贸n en el reducer, pero funcion贸.

// ./reducers/pokemon

   case SET_LOADING:
      return state.setIn(['loading'], action.payload);

// ./app

		const loading = useSelector(state => state.get('loading'));