So implementieren Sie Redux in 24 Zeilen JavaScript

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.

Redux-Counter-App-Demo

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 incrementausgelöst wird, erhöhen Sie state.count.
  • Wenn decrementgefeuert wird, dekrementieren state.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 listenersArray hinzugefügt . Dies ist wichtig, da jedes Mal, wenn jemand eine Aktion auslöst, alle Aktionen listenersin einer Schleife benachrichtigt werden müssen.

Wenn Sie yourReducermit undefinedund ein leeres Objekt aufrufen, wird das initialStateoben 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 actionals Parameter verwendet. Er ernährt sich das actionund das currentStatezu yourReducereinem bekommen neuen Zustand. Dann dispatchbenachrichtigt 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; } }; }; 

subscribeGibt eine Funktion zurück, die aufgerufen wird und unsubscribedie 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.

Redux-Counter-App-Demo

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.

Git-Merch-Screenshot-1-1

Git-Merch-Screenshot-2-1

Danke fürs Lesen

Weitere Inhalte wie diesen finden Sie unter //yazeedb.com!

Bis zum nächsten Mal!