Estiven Mahecha Henao
Rafael Soriano Ramírez
Seba Cardoso
Marc España Quinquilla
Seba Cardoso
Henry J. Perez
Miguel Angel Reyes Moreno
Juan Pablo Jimenez
Max Andy Diaz Neyra
David Condori Quispe
Andrés Felipe Eslava Zuluaga
Gualberto Montiel
Diego Fernando Velesaca Orellana
Cesar Pelaez
Max Andy Diaz Neyra
Matias Peressutti
Samuel Santana
Cayo Legal
Diego Vergara
Edgar Rolando Cosajay Campos
David Rangel
Juan Diego Mejia Maestre
Harold Zurita Simon
Jhoana España Urresty
Mariangelica Useche
Team PlatziGregori Piñeres
Cristian Contreras
DANIEL STEVEN RODRIGUEZ VERANO
Muchísimo mejor con hooks..
Más fácil, los temas vienen en las pruebas unitarias, unas por otras
Soy un viejo usuario de Redux. Hoy en dia uso solo los hooks. Me gusta mucho mas y para testear no se me complico tanto. Simplemente mockeo al estado actual y listo.
Gracias por el aporte Seba, Por la tendencia de los años, crees que Redux terminará integrado en React? Osea poder manejar el estado global sin descargar una librería extra.
Yo no creo que React integre Redux porque un principio basico de React es el de "abstracciones comunes": se refiere que a React no quiere incluir código inútil en su core, código que sea demasiado especifico para caso de uso demasiado concreto.
Tambien te puedo decir que podrias manejar un estado global solo con el Context Api que viene integrado dentor de React o usar otras librerias alternativas a Redux como Mobx
Redux en lo salvaje
Aparte del titulo de periodico que coloque, mi experiencia con Redux es que muchos proyectos utilizan el connect API para sus componentes.
Esto no solo se debe a que muchas veces se trata de proyectos comenzados antes de la existencia de los Hooks, sino tambien a una question de consistencia. Tanto a nivel de testing como menciono la profesora, como a nivel de desarrollo del codigo en general.
Personalmente veo mucho mas facil e intuitivo utilizar Hooks y componentes funcionales. Pero es bueno que conozcas las maneras "legacy" porque te lo vas a encontrar mucho en el ambito laboral.
Hooks vs. Connect
useSelector vs Connect
Redux ahora recomienda usar su Hooks API. - Redux Docs
Use the React-Redux Hooks API
const list = useSelector(state => state.list);const dispatch = useDispatch(); dispatch(myAction());9.-Hooks vs. Connect
-- useSelector vs Connect
-- Redux recomienda usar su Hooks API.
-- Hooks API
Dejo mi avance en TS:
// App.tsx import { useEffect, useState } from 'react' import { connect, useDispatch, useSelector } from 'react-redux' import { Col } from 'antd' import { Search } from './components/Search' import { PokemonList } from './components/PokemonList' import { getPokemons, PokemonType } from './api' import logo from './statics/logo.svg' import './App.css' import { setPokemons } from './actions' import { TypeState } from './reducers/pokemon' function App() { const pokemons = useSelector((state:TypeState)=>state.pokemons) const dispath = useDispatch(); useEffect(()=>{ async function fetchPokemon(){ const pkmns = await getPokemons(); dispath(setPokemons(pkmns as PokemonType[])) } fetchPokemon(); },[]) return ( <div className="App"> <Col span={4} offset={10}> <img src={logo} alt="Pokedux" /> </Col> <Col span={8} offset={8}> <Search /> </Col> <PokemonList pokemons={pokemons} /> </div> ) } export default App;
// pokemon.ts import { SET_POKEMONS } from "../actions/types" import { PokemonType } from "../api" export type TypeState = { pokemons: PokemonType[] } const initialState: TypeState = { pokemons: [] } export const pokemonReducer = (state:TypeState = initialState, action:any)=>{ switch(action.type){ case SET_POKEMONS: return {...state, pokemons: action.payload} default: return state } }
Comencé el proyecto con TypeScript y acá tiro el resumen:
// ** index.tsx // Acá de crea el store. // Por medio del provider de redux se pasa el reducer, que contiene el state import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import { pokemonsReducer } from './reducers/pokemons'; import { Provider } from 'react-redux'; import { legacy_createStore as createStore } from 'redux' import './index.css'; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); const store = createStore(pokemonsReducer); root.render( <Provider store={store}> <React.StrictMode> <App /> </React.StrictMode> </Provider> );
·
//** reducers/pokemons.ts // Acá se inicializa el state. // Creamos la función reducer: función que recibe *el state* y *el action*. // El action contiene: el type del action y el payload. // Se evalúa el type del action, para devolver el state correcto con lo que contine el payload. import { PokemonType } from "../api"; import { SET_POKEMONS } from "../actions/types"; type InitialPokemonsStateType = { pokemons: PokemonType[] }; const initialState: InitialPokemonsStateType = { pokemons: [] } export const pokemonsReducer = ( state: InitialPokemonsStateType = initialState, action: any ) => { switch(action.type) { case SET_POKEMONS: return { ...state, pokemons: action.payload, }; default: return state; } };
·
// ** actions/index.ts // El action es una función que recibe un payload. // Devuelve un objeto con el type y el payload que recibe. import { PokemonType } from "../api"; import { SET_POKEMONS } from "./types"; export const setPokemons = (payload: PokemonType) => ({ type: SET_POKEMONS, payload, });}
// actions/type.ts export const SET_POKEMONS = 'SET_POKEMONS';
·
// ** api/index.ts // Acá se crea el llamado a la API y los tipados globales. import axios from "axios" export type PokemonType = { name: string; url: string; }; export type PokemonResponse = { results: PokemonType[]; } const getPokemon = async () => { const URL = 'https://pokeapi.co/api/v2/pokemon?limit=151'; try { const { data: { results } } = await axios.get(URL); return results; } catch (err) { console.error('err '.repeat(5), err); } } export default getPokemon;
·
//** App.tsx // Acá suscribimos el componente al state con useSelector // También se dispara la acción con useDispatch para que llame los pokemons y se ejecute el reducer // El reducer actualiza el estado global de la aplicación import React, { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Col } from 'antd'; import Searcher from './components/Searcher'; import PokemonList from './components/PokemonList'; import getPokemon, { PokemonType } from './api'; import { setPokemons } from './actions' import logo from './statics/logo.svg'; import './App.css'; type AppType = { pokemons: PokemonType[], setPokemons: any, } function App() { const pokemons = useSelector((state: AppType) => state.pokemons); const dispatch = useDispatch() useEffect(() => { const fetchPokemons = async () => { const response = await getPokemon(); dispatch(setPokemons(response)); } fetchPokemons(); }, []); console.log('pokemons ', pokemons) return ( <div className='App'> <Col span={4} offset={10}> <img src={logo} alt='Pokedux'/> </Col> <Col span={8} offset={8}> <Searcher /> </Col> <PokemonList results={pokemons} /> </div> ); } export default App;
Ventajas de "Hook": Permite una escritura más limpia y sencilla de los componentes de React. Facilita la reutilización de código y la composición de funcionalidades. Mejora la legibilidad del código al separar la lógica de los componentes de React. Ventajas de "Connect":
Ofrece una forma centralizada y eficiente de gestionar el estado global de la aplicación. Facilita la implementación de patrones de diseño como la arquitectura Flux. Mejora la escalabilidad de la aplicación al mantener una única fuente de verdad para el estado.
Soy nuevo en React y en realidad me queda la duda de que se debería considerar para decidir si usar Redux o los Hooks ? Desde mi punto de vista veo que es mucho más fácil y amigables usar los Hooks.
Te refieres a que consideracion tener en cuenta para determinar si usar los hooks de react o a los hooks de redux?
Respuesta contundente: utiliza los hooks. Resulta que hacen lo mismo pero los hooks mejoran la experiencia de desarrollo. Ambos son correctos, Redux con connect se hizo con la filosifia antigua y ahora Redux con hooks se hace con la filosifia actual. En React prioriza funciones sobre clases, al final son lo mismo pero al desarrollar las funciones son mejores.
No logro entender cómo es que se termina conectando con el reducer, ya que no es mencionado/invocado en ninguna línea dentro de App.js. Me confunde mucho.
Por si te ayuda, yo me tuve que hacer un esquema para entenderlo mejor. Si algún compañero/a detecta algún fallo, le agradecería que lo comentará, ya que me ayudará a mi también a entenderlo mejor.
X2, me gustaría una explicación sobre eso
Amo los hooks, además sigue la misma forma de trabajar el traspaso de información con react que en los cursos anteriores.
si se ejecuta dispactch de la accion se renderiza de nuevo el selector
Así se vería con TS:
const pokemons = useSelector( (state: RootState) => state.pokemonData.pokemons, ); const dispatch = useDispatch(); useEffect(() => { const fetchPokemons = async () => { const pokeRes = await getPokemon(); if (pokeRes) { dispatch(setPokemons(pokeRes)); } }; fetchPokemons(); }, [getPokemon, setPokemons]);
⚛️ Redux Hooks: Guía Rápida de Implementación
Pasar de connect (HOC) a Hooks es el estándar moderno en React. Reduce el "boilerplate" (código repetitivo) y mejora la legibilidad de forma increíble.
🚀 ¿Por qué usar Hooks en lugar de connect?
mapStateToProps y mapDispatchToProps.🛠️ Los Hooks Esenciales
useSelector:
useDispatch:
dispatch para enviar acciones al Store.🔄 Proceso de Migración (Refactoring)
connect(...) al exportar.{ useSelector, useDispatch } de react-redux.💻 Ejemplo Práctico (Sintaxis Moderna)
import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { setPokemon } from './actions'; const PokemonComponent = () => { // 1. Obtenemos el estado directamente const pokemonList = useSelector(state => state.pokemonList); // 2. Obtenemos el disparador de acciones const dispatch = useDispatch(); const handleSetPokemon = () => { dispatch(setPokemon()); }; return ( <div> {pokemonList.map(p => <p key={p.id}>{p.name}</p>)} <button onClick={handleSetPokemon}>✨ Cargar Pokémon</button> </div> ); }; export default PokemonComponent;
🧠 Redux con Hooks
Redux también nos proporciona una API basada en hooks que podemos utilizar dentro de nuestros componentes funcionales.
Las principales diferencias con el patrón clásico (connect) son:
⚙️ Boilerplate
Con el patrón tradicional de Redux, debíamos crear dos elementos —mapStateToProps y mapDispatchToProps— y luego envolver nuestro componente con el método connect.
Toda esa configuración generaba mucho boilerplate, es decir, código repetitivo y poco legible.
Con los hooks (useSelector y useDispatch), obtenemos el mismo resultado con solo un par de líneas, haciendo el código más simple y directo.
🧩 Separación de responsabilidades
Cuando usamos connect, este método crea un High Order Component (HOC).
El HOC es el encargado de renderizar nuestro componente y de inyectarle el estado y las acciones (actions) como props.
Con los hooks, esa conexión se hace directamente dentro del componente, sin HOCs intermedios.
Esto permite una mejor separación de responsabilidades y una arquitectura más moderna basada en funciones.
🧪 Testing
Hacer testing puede resultar un poco más sencillo con connect, ya que el componente recibe el estado y los dispatchers como props, por lo que basta con pasarle props simuladas.
En cambio, con los hooks, el componente necesita estar realmente conectado al store de Redux durante las pruebas.
Esto requiere envolverlo con un Provider en el entorno de testing, aunque no es un gran inconveniente.
💡 Recomendación oficial
Redux recomienda utilizar su API de hooks porque:
🧰 Hooks principales de Redux
La API de hooks tiene dos funciones principales:
🔸 useSelector
Nos permite extraer datos del estado global mediante una función selectora.
Esta función debe ser pura, es decir, no depender de variables externas.
Su funcionamiento es similar a mapStateToProps, pero con la diferencia de que:
dispatch de una acción, verificando si el valor cambió para decidir si debe volver a renderizarse.🔸 useDispatch
Nos devuelve una referencia al dispatcher del store, que utilizamos para disparar acciones (actions) de Redux.
Equivale a mapDispatchToProps, pero en una forma mucho más simple.
🪄 Implementación mediante un Custom Hook
Podemos encapsular la lógica de Redux dentro de un custom hook, por ejemplo usePokemons.js:
import { useDispatch, useSelector } from 'react-redux'; import { setPokemons } from '../actions'; export const usePokemons = () => { const pokemons = useSelector((state) => state.pokemons); const dispatch = useDispatch(); const handleSetPokemons = (pokemonsData) => { dispatch(setPokemons(pokemonsData)); }; return { pokemons, setPokemons: handleSetPokemons, }; };
Luego podemos eliminar el patrón tradicional con connect y usar nuestro custom hook directamente:
import { Col } from "antd"; import Searcher from "./components/Searcher"; import PokemonList from "./components/PokemonList"; import logo from "./statics/logo.svg"; import "./App.css"; import { getPokemon } from "./api"; import { useEffect } from "react"; import { usePokemons } from "./hooks/usePokemons"; function App() { const { pokemons, setPokemons } = usePokemons(); useEffect(() => { const fetchPokemons = async () => { const pokemonsRes = await getPokemon(); setPokemons(pokemonsRes); }; fetchPokemons(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( <div className="App"> <Col span={4} offset={10}> <img src={logo} alt="Pokedux" /> </Col> <Col span={8} offset={8}> <Searcher /> </Col> <PokemonList pokemons={pokemons} /> </div> ); } export default App;
tengo este error
Uncaught TypeError: pokemons.map is not a function
import './pokemonList.css' import FuckCard from './FuckCard' const FuckList = ({ pokemons }) => { console.log(pokemons); return ( <div className='PokemonList'> {pokemons.map((pokemon) => { return <FuckCard name={pokemon.name} key={pokemon.name} img={pokemon.url} /> })} </div> ) } FuckList.defaultProps = { pokemons: Array(10).fill(''), }; export default FuckList
Tienes un default prop, sin embargo parece que estás mandado null u otra cosa a tu componente. ¿Qué te pinta ese console.log?
¿Podemos usar alternativas como @preact/signals como una state manager global de nuestra aplicación?
useSelector es un hook que permite extraer datos del estado de Redux, utilizando una función selectora. Este hook se suscribe automáticamente a los cambios en el estado y se vuelve a renderizar el componente cuando el dato seleccionado cambia.
Por otro lado, useDispatch retorna una referencia a la función dispatch de Redux, que se utiliza para enviar acciones al store. Ambos hooks simplifican el código y mejoran la experiencia de desarrollo al eliminar la necesidad de crear componentes de orden superior como connect.
const list = useSelector(state => state.list)
mapstatetoprops, solo que el valor se guarda en una variable. el selector será llamado cada que se haga distpatch de una accion para evaluar si se renderiza de nuevo un componenteuseSelector es semejante a state de const [state, setState] = useState() osea que podemos sacar datos de hay solo que tenemos que especificar de donde los queremos sacar o de que parte del reducer lo queremos sacar el state o los datos. la maquina osea useSelector entiende automaticamente de donde va a sacar el state del reducer tan solo tenemos que especificarlo como const pokemons = useSelector((state) => state.pokemons) que le estamos sacando los datos de la APIconst dispatch = useDispatch() dispatch(myAction())
const dispatch = useDispatch() dispatch(myAction()) es semejante al setState de const [state, setState] = useState() osa que podemos enviar cualquier datos al action de los objetos dispatch(setLoading(true)) que anteriormente hicimos y cuando el objeto retorne sus valores como el type y el payload le lo estaremos enviando al store de Redux y el store selo enviara al action y este lo actualizara los state indicados, que posteriormente los llamaremos con useSelector