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 24

Preguntas 3

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Por si a alguien le pasa como a mi que no puede instalar la dependencia, recuerden que es “immutable” con doble “m” y no “inmutable” 😅

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ó “immutable”: “^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'));

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.

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.

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))

valida la información , pero me parece más complicado que el método nativo de js spread operator

Buen aporte, pero sinceramente me quedo con lo que nos ofrece JS por defecto. Además, me parece que estamos haciendo el proyecto dependiente, cada vez más de más librerías. Entre menos librerías se usen es mucho mejor; por escalabilidad, por mantenibilidad y por performance. Ir haciendo que un proyecto dependa de tantas extensiones de librerías, hace que el proyeto a futuro sea más complicado de mantener.
hola a todos, les dejo acá él link de la librería immutable.js actualizada que la que esta en recursos no esta funcionando. <https://immutable-js.com/#getting-started>
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 **“immer” **en ves de el uso de “immutable”, 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 “redux-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"));

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…

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
    }
}

me quedo con el spread operator…

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)

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'));