90% Konvention, 10% Bibliothek.
Redux gehört zu den wichtigsten JavaScript-Bibliotheken, die jemals erstellt wurden. Inspiriert von Stand der Technik wie Flux und Elm brachte Redux die funktionale JavaScript-Programmierung auf die Karte, indem eine skalierbare Architektur mit drei einfachen Punkten eingeführt wurde.
Wenn Sie Redux noch nicht kennen, lesen Sie zuerst die offiziellen Dokumente.
Redux ist meistens Konvention
Betrachten Sie diese einfache Zähleranwendung, die die Redux-Architektur verwendet. Wenn Sie weiterspringen möchten, schauen Sie sich das Github-Repo an.
Staat lebt in einem einzigen Baum
Der Status der Anwendung sieht folgendermaßen aus.
const initialState = { count: 0 };
Aktionen deklarieren Statusänderungen
Durch die Redux-Konvention ändere (mutiere) ich den Zustand nicht direkt.
// DON'T do this in a Redux app state.count = 1;
Stattdessen erstelle ich alle Aktionen, die der Benutzer in der Anwendung nutzen kann.
const actions = { increment: { type: 'INCREMENT' }, decrement: { type: 'DECREMENT' } };
Der Reduzierer interpretiert die Aktion und aktualisiert den Status
Das letzte architektonische Stück erfordert einen Reduzierer, eine reine Funktion, die eine neue Kopie Ihres Status basierend auf dem vorherigen Status und der vorherigen Aktion zurückgibt.
- Wenn
increment
ausgelöst wird, erhöhen Siestate.count
. - Wenn
decrement
gefeuert wird, dekrementierenstate.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; } };
Bisher kein Redux
Haben Sie bemerkt, dass wir die Redux-Bibliothek noch nicht berührt haben? Wir haben gerade einige Objekte und eine Funktion erstellt. Dies ist, was ich mit "meistens Konvention" meine, 90% von Redux benötigen kein Redux!
Lassen Sie uns Redux implementieren
Um diese Architektur nutzen zu können, müssen wir sie an ein Geschäft anschließen. Wir werden nur eine Funktion implementieren - createStore
.
Es wird so verwendet.
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 }
Und hier ist unser erstes Boilerplate. Wir benötigen eine Liste der Listener und den vom Reduzierer bereitgestellten Ausgangszustand.
const createStore = (yourReducer) => { let listeners = []; let currentState = yourReducer(undefined, {}); }
Immer wenn jemand unseren Shop abonniert, wird er dem listeners
Array hinzugefügt . Dies ist wichtig, da jedes Mal, wenn jemand eine Aktion auslöst, alle Aktionen listeners
in einer Schleife benachrichtigt werden müssen.
Wenn Sie yourReducer
mit undefined
und ein leeres Objekt aufrufen, wird das initialState
oben installierte zurückgegeben. Dies gibt uns einen angemessenen Wert, den wir zurückgeben können, wenn wir anrufen store.getState()
. Apropos, lassen Sie uns diese Methode erstellen.
store.getState ()
Dies ist eine Funktion, die den neuesten Status aus dem Speicher zurückgibt. Wir benötigen dies, um unsere Benutzeroberfläche jedes Mal zu aktualisieren, wenn der Benutzer auf eine Schaltfläche klickt.
const createStore = (yourReducer) => { let listeners = []; let currentState = yourReducer(undefined, {}); return { getState: () => currentState }; }
store.dispatch (Aktion)
Dies ist eine Funktion, die a action
als Parameter verwendet. Er ernährt sich das action
und das currentState
zu yourReducer
einem bekommen neuen Zustand. Dann dispatch
benachrichtigt jeder, der das abonniert hat 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 (Listener)
Dies ist eine Funktion, mit der Sie benachrichtigt werden können, wenn der Store eine Aktion erhält. Hier können Sie store.getState()
Ihren neuesten Status abrufen und Ihre Benutzeroberfläche aktualisieren.
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
Gibt eine Funktion zurück, die aufgerufen wird und unsubscribe
die Sie aufrufen können, wenn Sie nicht mehr daran interessiert sind, die Aktualisierungen des Geschäfts anzuhören.
Jetzt alle zusammen
Lassen Sie uns dies an unsere Schaltflächen anschließen und den endgültigen Quellcode anzeigen.
// 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); });
Und noch einmal hier ist unsere endgültige Benutzeroberfläche.
Wenn Sie an dem von mir verwendeten HTML / CSS interessiert sind, finden Sie hier wieder das GitHub-Repo!
Willst du kostenloses Coaching?
Wenn Sie einen kostenlosen Anruf planen möchten, um Fragen zur Front-End-Entwicklung in Bezug auf Code, Interviews, Karriere oder andere Themen zu besprechen, folgen Sie mir auf Twitter und DM me.
Wenn Sie unser erstes Treffen genießen, können wir anschließend ein laufendes Coaching besprechen, um Sie beim Erreichen Ihrer Front-End-Entwicklungsziele zu unterstützen!
Tragen Sie Ihre Beiträge
Wenn Sie jeden Tag programmieren, insbesondere wenn Sie sich für GitHub engagieren, wäre es nicht cool, diese Beitragskarte für alle sichtbar zu tragen?
Mit Gitmerch.com können Sie ein T-Shirt Ihrer GitHub-Beitragskarte drucken! Verwenden Sie den Code Yazeed an der Kasse, um einen Rabatt zu erhalten.
Danke fürs Lesen
Weitere Inhalte wie diesen finden Sie unter //yazeedb.com!
Bis zum nächsten Mal!