90% convención, 10% biblioteca.
Redux se encuentra entre las bibliotecas de JavaScript más importantes jamás creadas. Inspirado en la técnica anterior como Flux y Elm, Redux puso la programación funcional de JavaScript en el mapa al introducir una arquitectura escalable de tres puntos simples.
Si es nuevo en Redux, considere leer los documentos oficiales primero.
Redux es principalmente Convención
Considere esta sencilla aplicación de contador que utiliza la arquitectura Redux. Si desea avanzar, consulte el repositorio de Github.
El estado vive en un solo árbol
El estado de la aplicación se ve así.
const initialState = { count: 0 };
Las acciones declaran cambios de estado
Por convención de Redux, no modifico (muto) directamente el estado.
// DON'T do this in a Redux app state.count = 1;
En su lugar, creo todas las acciones que el usuario puede aprovechar en la aplicación.
const actions = { increment: { type: 'INCREMENT' }, decrement: { type: 'DECREMENT' } };
El reductor interpreta la acción y actualiza el estado
La última pieza arquitectónica requiere un reductor, una función pura que devuelve una nueva copia de su estado en función del estado y la acción anteriores.
- Si
increment
se dispara, incrementestate.count
. - Si
decrement
se dispara, decrementarstate.count
.
const countReducer = (state = initialState, action) => { switch (action.type) { case actions.increment.type: return { count: state.count + 1 }; case actions.decrement.type: return { count: state.count - 1 }; default: return state; } };
No hay Redux hasta ahora
¿Notaste que aún no hemos tocado la biblioteca de Redux? Acabamos de crear algunos objetos y una función. Esto es lo que quiero decir con "principalmente convención", ¡el 90% de Redux no requiere Redux!
Implementemos Redux
Para poner esta arquitectura en uso, debemos conectarla a una tienda. Implementaremos solo una función– createStore
.
Se usa así.
import { createStore } from 'redux' const store = createStore(countReducer); store.subscribe(() => { console.log(store.getState()); }); store.dispatch(actions.increment); // logs { count: 1 } store.dispatch(actions.increment); // logs { count: 2 } store.dispatch(actions.decrement); // logs { count: 1 }
Y aquí está nuestro modelo inicial. Necesitaremos una lista de oyentes y el estado inicial proporcionado por el reductor.
const createStore = (yourReducer) => { let listeners = []; let currentState = yourReducer(undefined, {}); }
Cada vez que alguien se suscribe a nuestra tienda, se agrega a la listeners
matriz. Es importante porque cada vez que alguien envía una acción, todos listeners
deben ser notificados en un bucle.
Llamar yourReducer
con undefined
y un objeto vacío devuelve el initialState
que instalamos arriba. Esto nos da un valor adecuado para devolver cuando llamamos store.getState()
. Hablando de eso, creemos ese método.
store.getState ()
Esta es una función que devuelve el último estado de la tienda. Necesitaremos esto para actualizar nuestra interfaz de usuario cada vez que el usuario haga clic en un botón.
const createStore = (yourReducer) => { let listeners = []; let currentState = yourReducer(undefined, {}); return { getState: () => currentState }; }
store.dispatch (acción)
Esta es una función que toma action
como parámetro. Se alimenta de que action
y el currentState
de yourReducer
conseguir un nuevo estado. Luego dispatch
notifica a todas las personas suscritas al store
.
const createStore = (yourReducer) => { let listeners = []; let currentState = yourReducer(undefined, {}); return { getState: () => currentState, dispatch: (action) => { currentState = yourReducer(currentState, action); listeners.forEach((listener) => { listener(); }); } }; };
store.subscribe (oyente)
Esta es una función que le permite ser notificado cuando la tienda recibe una acción. Es bueno usarla store.getState()
aquí para obtener su último estado y actualizar su interfaz de usuario.
const createStore = (yourReducer) => { let listeners = []; let currentState = yourReducer(undefined, {}); return { getState: () => currentState, dispatch: (action) => { currentState = yourReducer(currentState, action); listeners.forEach((listener) => { listener(); }); }, subscribe: (newListener) => { listeners.push(newListener); const unsubscribe = () => { listeners = listeners.filter((l) => l !== newListener); }; return unsubscribe; } }; };
subscribe
devuelve una función llamada a la unsubscribe
que puede llamar cuando ya no esté interesado en escuchar las actualizaciones de la tienda.
Todos juntos ahora
Conectemos esto a nuestros botones y veamos el código fuente final.
// simplified createStore function const createStore = (yourReducer) => { let listeners = []; let currentState = yourReducer(undefined, {}); return { getState: () => currentState, dispatch: (action) => { currentState = yourReducer(currentState, action); listeners.forEach((listener) => { listener(); }); }, subscribe: (newListener) => { listeners.push(newListener); const unsubscribe = () => { listeners = listeners.filter((l) => l !== newListener); }; return unsubscribe; } }; }; // Redux architecture pieces const initialState = { count: 0 }; const actions = { increment: { type: 'INCREMENT' }, decrement: { type: 'DECREMENT' } }; const countReducer = (state = initialState, action) => { switch (action.type) { case actions.increment.type: return { count: state.count + 1 }; case actions.decrement.type: return { count: state.count - 1 }; default: return state; } }; const store = createStore(countReducer); // DOM elements const incrementButton = document.querySelector('.increment'); const decrementButton = document.querySelector('.decrement'); // Wire click events to actions incrementButton.addEventListener('click', () => { store.dispatch(actions.increment); }); decrementButton.addEventListener('click', () => { store.dispatch(actions.decrement); }); // Initialize UI display const counterDisplay = document.querySelector('h1'); counterDisplay.innerHTML = parseInt(initialState.count); // Update UI when an action fires store.subscribe(() => { const state = store.getState(); counterDisplay.innerHTML = parseInt(state.count); });
Y una vez más, aquí está nuestra interfaz de usuario final.
Si está interesado en el HTML / CSS que utilicé, ¡aquí está el repositorio de GitHub nuevamente!
¿Quieres coaching gratuito?
Si desea programar una llamada gratuita para discutir preguntas de desarrollo de Front-End con respecto al código, entrevistas, carrera o cualquier otra cosa, sígame en Twitter y envíeme un mensaje de correo electrónico.
Después de eso, si disfruta de nuestra primera reunión, ¡podemos discutir un entrenamiento continuo para ayudarlo a alcanzar sus objetivos de desarrollo de Front-End!
Use sus contribuciones
Si está codificando todos los días, especialmente si se está comprometiendo con GitHub, ¿no sería genial usar ese mapa de contribución para que todos lo vean?
¡Gitmerch.com te permite imprimir una camiseta de tu mapa de contribución de GitHub! Utilice el código, Yazeed , al finalizar la compra para obtener un descuento.
Gracias por leer
Para obtener más contenido como este, visite //yazeedb.com.
¡Hasta la proxima vez!