German Cavani
Erick Stalyn Pacherrez Puyén
Invitado Certificado
Miguel Angel Reyes Moreno
José Antonio Casadiego Gimenez
Juan Camilo Lentino Villalba
Alex Guaman
Daniel Socorro Castellano
Andres Gallego
Jhon Sebastián Delgado Almendrales
Willian Sanchez
Andrés Felipe Eslava Zuluaga
Carlos Eduardo Bracho Ramírez
Diego Vergara
Andrés Felipe Eslava Zuluaga
Violeta Saraí Vera Salazar
Violeta Saraí Vera Salazar
Gilbert Ardila
Jhon Sebastián Delgado Almendrales
milton coronado
Jhonatan Villamizar
Juan Camilo Lentino Villalba
Kevin Figuera
Ivan González
Sergio Andres Campbell Villarreal
Luis Eduardo Martínez Espinoza
Juan Diego Mejia Maestre
Walter Castro
Daniel Alberto Vega Bejarano
Irving Juárez
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" 😅
Jajajajajajaja Okey man ><
gracias jajaj
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í.
Si, tienes razón. Si no da error.
también podríamos colocarlo de esta forma
case SET_LOADING: return state.set('loading', action.payload)
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'));
muchas gracias ! tambien habia instalado la version de “immutable”: “^4.1.0”, modifique ambos archivos con tu codigo y me funciono. Solo una pequeña observacion, despues del fromJS esta action.action. repetido, solo eso, y ademas de importar tambien los metodos al comienzo de esos archivos, tanto en el App.js y el pokemons.js, asi lo puse yo :
import { fromJS, setIn, get, getIn} 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_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; } };
y el App.js asi :
import { useEffect} from 'react'; import { Col, Spin } from 'antd'; import { useDispatch, useSelector } from 'react-redux'; import Searcher from './components/Searcher'; import PokemonList from './components/PokemonList'; import { getPokemon } from './api'; import { getPokemonsWithDetails, setLoading } from './actions'; import logo from './statics/logo.svg'; 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)); dispatch(setLoading(false)); }; 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;
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.
No eres el único que piensa eso bro...
Tambien pienso lo mismo. Aunque la clase nos aclara que hay otras forma de hacer las cosas y no reiventar la rueda. Esto es como una tool dentro del set de conocimientos.
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.
Buenas tardes. Quisiera saber si esta librería immutable.js es común y aceptada en el desarrollo con Redux, o es una propuesta solamente. Porque así puedo saber si enfocarme en aprenderla de lleno o centrarme en otras prioridades para el desarrollo.
Me pregunto lo mismo, no se cual es la ventaja de usar immutable en vez de los metodos propios de javascript.
Es solo una propuesta. Puesto que la inmutabilidad en JS la profesora la demostró en la clase anterior. En este caso, lo que se propone es que el desarrollador no caiga en el error de mutar el objeto que va a manipular. . Immutable dice:
biblioteca que admite una estructura de datos inmutable. Significa que los datos una vez creados no se pueden cambiar. Hace que el mantenimiento de estructuras de datos inmutables sea más fácil y eficiente. .
En mi caso, prefiero usar JS por modo Vanilla sin agregados. Pues recuerden lo que laprofesora dice en la clase anterior: Reduz solo actualiza cuando el estado final es diferente del inicial
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))
En comentario se ve la comparativa sin el uso de immutable, como se muestra en la clase y como es ahora Además, get y set (sin el In) permanecen igual como en la clase
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.
me quedo con el spread operator...
hola a todos, les dejo acá él link de la librería immutable.js actualizada que la que esta en recursos no esta funcionando.
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"));
🔒 Guía Pro: Inmutabilidad con ImmutableJS
La inmutabilidad no es solo una moda; es una estrategia para evitar que diferentes partes de tu código cambien los mismos datos por accidente, algo vital en React para que el "Virtual DOM" sepa exactamente qué cambió.
🚀 1. Instalación y Corazón del Concepto
ImmutableJS transforma objetos y arrays en estructuras que no se pueden tocar. Si quieres "cambiar" algo, la librería te da una copia nueva con el cambio aplicado.
npm install immutable🏗️ 2. Estructuras de Datos
{}.[].import { fromJS } from 'immutable'; const state = fromJS({ pokemons: [ { id: 1, name: 'Pikachu', type: 'Electric' } ], ui: { loading: false } });
✍️ 3. Manipulación Precisa (Getters y Setters)
Olvídate de hacer ...state (spread operator) diez veces para llegar a un objeto anidado.
getIn(['ruta', 'hijo']): Accede a datos profundos sin que la app falle si un padre es nulo.setIn(['ruta'], valor): Cambia un valor específico y devuelve el nuevo estado.updateIn(['ruta'], val => val + 1): (Extra) Ideal para contadores o lógica que depende del valor anterior.findIndex(): Localiza elementos en una lista rápidamente.// Actualización profunda simplificada const index = state.get('pokemons').findIndex(p => p.get('id') === 1); const newState = state.setIn(['pokemons', index, 'name'], 'Raichu');
🔥 4. Funciones de Alto Nivel (Más info)
Para que tus notas sean de nivel senior, he añadido estos dos métodos que no estaban en tu texto:
Immutable.is(A, B): Compara dos estructuras por su valor, no por su referencia. Muy útil para shouldComponentUpdate.
withMutations(): Si tienes que hacer 50 cambios seguidos, este método los agrupa en una sola operación para que el rendimiento no caiga.
A. Comparación por Valor con Immutable.is()
A diferencia de ===, que compara si dos objetos están en la misma dirección de memoria, is() compara si el contenido es idéntico.
import { Map, is } from 'immutable'; const mapA = Map({ a: 1, b: 2 }); const mapB = Map({ a: 1, b: 2 }); console.log(mapA === mapB); // false (son instancias diferentes en memoria) console.log(is(mapA, mapB)); // true (su contenido es exactamente igual) // Caso de uso: shouldComponentUpdate en React // Evita re-renders innecesarios si los datos no han cambiado realmente.
B. Optimización Masiva con withMutations()
Si tienes que aplicar 100 cambios, hacer 100 copias intermedias es lento. withMutations crea un estado "temporalmente mutable" para hacer todos los cambios de una vez y devolver un solo objeto nuevo al final.
import { List } from 'immutable'; const listaOriginal = List([1, 2, 3]); const listaOptimizada = listaOriginal.withMutations(mutable => { for (let i = 4; i <= 100; i++) { // Estas operaciones no crean copias intermedias mutable.push(i); } }); // Aquí se genera la única copia final inmutable. console.log(listaOptimizada.size); // 100
Que barbaridad de boilerplate
Genial aprender esta librería, aunque puede complicarse el escalar y mantener un producto a largo plazo.
Es realmente necesario agregar una libreria extra para ahorrarnos unas cuantas lineas de codigo al buscar el index del pokemon?