Erste Schritte mit Redux für JavaScript State Management

0
146

Redux ist ein Statusverwaltungstool, das speziell für clientseitige JavaScript-Anwendungen entwickelt wurde die stark von komplexen Daten und externen APIs abhängen, und bietet großartige Entwicklertools, die die Arbeit mit Ihren Daten erleichtern.

Was macht Redux?< /h2>

Einfach ausgedrückt ist Redux ein zentralisierter Datenspeicher. Alle Ihre Bewerbungsdaten werden in einem großen Objekt gespeichert. Die Redux Devtools machen dies einfach zu visualisieren:

Dieser Zustand ist unveränderlich, was zunächst ein seltsames Konzept ist, aber aus einigen Gründen sinnvoll ist. Wenn Sie den Status ändern möchten, müssen Sie eine Aktion senden, die im Wesentlichen einige Argumente benötigt, eine Nutzlast bildet und an Redux sendet. Redux übergibt den aktuellen Status an eine Reduzierfunktion, die den vorhandenen Status ändert und einen neuen Status zurückgibt, der den aktuellen ersetzt und ein Neuladen der betroffenen Komponenten auslöst. Sie können beispielsweise einen Reduzierer haben, um einer Liste ein neues Element hinzuzufügen oder ein bereits vorhandenes Element zu entfernen oder zu bearbeiten.

Wenn Sie dies auf diese Weise tun, erhalten Sie nie ein undefiniertes Verhalten mit Ihrem App-Änderungsstatus nach Belieben. Da es eine Aufzeichnung jeder Aktion und deren Änderung gibt, ermöglicht es auch das Debuggen auf Zeitreisen, bei dem Sie Ihren Anwendungsstatus zurückscrollen können, um zu debuggen, was mit jeder Aktion passiert (ähnlich wie bei einem Git-Verlauf).

Redux kann mit jedem Frontend-Framework verwendet werden, wird jedoch häufig mit React verwendet, und darauf konzentrieren wir uns hier. Unter der Haube verwendet Redux die Context API von React, die ähnlich wie Redux funktioniert und sich für einfache Apps eignet, wenn Sie ganz auf Redux verzichten möchten. Die Devtools von Redux sind jedoch fantastisch, wenn Sie mit komplexen Daten arbeiten, und sie sind sogar optimierter, um unnötige Neudarstellungen zu vermeiden.

Werbung

Wenn Sie TypeScript verwenden, Die Dinge sind viel komplizierter, um Redux streng typisiert zu bekommen. Folgen Sie stattdessen dieser Anleitung, die typsichere Aktionen verwendet, um die Aktionen und Reduzierungen typfreundlich zu handhaben.

Strukturierung Ihr Projekt

Zuerst möchten Sie Ihre Ordnerstruktur gestalten. Dies liegt an Ihnen und den Stilpräferenzen Ihres Teams, aber im Grunde gibt es zwei Hauptmuster, die die meisten Redux-Projekte verwenden. Die erste besteht darin, jeden Dateityp (Action, Reducer, Middleware, Side-Effect) einfach in einen eigenen Ordner aufzuteilen, etwa so:

store/actions/Reducers/sagas/Middleware/index.js

Dies ist jedoch nicht das Beste, da Sie häufig sowohl eine Aktions- als auch eine Reduzierungsdatei für jede hinzugefügte Funktion benötigen. Es ist besser, die Aktions- und Reduzierungsordner zusammenzuführen und nach Funktionen aufzuteilen. Auf diese Weise befinden sich jede Aktion und der entsprechende Reducer in derselben Datei. Sie

speichern/features/todo/etc/sagas/middleware/root-reducer.js root-action.js index.js

Dies bereinigt die Importe, da Sie jetzt sowohl die Aktionen als auch die Reducer in importieren können dieselbe Anweisung mit:

import { todosActions, todosReducer } from 'store/features/todos'

Es liegt an Ihnen, ob Sie Redux-Code in einem eigenen Ordner (/store in den obigen Beispielen) aufbewahren oder in den Stammordner src Ihrer App integrieren möchten. Wenn Sie bereits Code pro Komponente trennen und viele benutzerdefinierte Aktionen und Reduzierungen für jede Komponente schreiben, sollten Sie die Ordner /features/ und /components/ zusammenführen und JSX-Komponenten neben Reduzierungscode speichern.< /p>

Wenn Sie Redux mit TypeScript verwenden, können Sie in jedem Funktionsordner eine zusätzliche Datei hinzufügen, um Ihre Typen zu definieren.

Installieren und Konfigurieren von Redux

Installieren Sie Redux und React-Redux von NPM:

npm install redux React-Redux

Sie möchten wahrscheinlich auch redux-devtools:

npm install –save-dev redux-devtools

Das erste, was Sie erstellen möchten, ist Ihr Shop. Speichern Sie dies als /store/index.js

import { createStore } from 'redux' import rootReducer from './root-reducer' const store = createStore(rootReducer) export default store; Werbung

Natürlich wird Ihr Geschäft komplizierter, wenn Sie Dinge wie Nebeneffekt-Add-Ons, Middleware und andere Dienstprogramme wie Connected-React-Router hinzufügen, aber das ist alles, was im Moment erforderlich ist. Diese Datei verwendet den Root Reducer und ruft mit ihm createStore() auf, der für die Verwendung durch die App exportiert wird.

Als nächstes erstellen wir eine einfache Aufgabenlistenfunktion. Sie werden wahrscheinlich damit beginnen wollen, die für diese Funktion erforderlichen Aktionen und die an sie übergebenen Argumente zu definieren. Erstellen Sie einen /features/todos/ Ordner und speichern Sie Folgendes als types.js:

export const ADD = 'ADD_TODO' export const DELETE = 'DELETE_TODO' export const EDIT = 'EDIT_TODO'

Dies definiert einige String-Konstanten für die Aktionsnamen. Unabhängig von den Daten, die Sie weitergeben, hat jede Aktion eine Typeigenschaft, bei der es sich um eine eindeutige Zeichenfolge handelt, die die Aktion identifiziert.

Sie müssen keine solche Typdatei haben, da Sie einfach den Zeichenfolgennamen der Aktion eingeben können, aber es ist für die Interoperabilität besser, dies auf diese Weise zu tun. Du könntest beispielsweise todos.ADD und Erinnerungen.ADD in derselben App haben, was dir die Mühe erspart, jedes Mal _TODO oder _REMINDER einzugeben, wenn du auf eine Aktion für diese Funktion referenzierst.

Speichern Sie als Nächstes Folgendes as /store/features/todos/actions.js:

import * as types from './types.js' export const addTodo = text => ({ type: types.ADD, text }) export const deleteTodo = id => ({ type: types.DELETE, id }) export const editTodo = (id, text) => ({ type: types.EDIT, id, text })

Dies definiert einige Aktionen, die die Typen aus den String-Konstanten verwenden, und legt die Argumente und die Erstellung von Nutzlasten für jede einzelne fest. Diese müssen nicht vollständig statisch sein, da es sich um Funktionen handelt. Ein Beispiel, das Sie verwenden könnten, ist das Festlegen einer Laufzeit-CUID für bestimmte Aktionen.

Werbung

Der komplizierteste Teil von Code, und wo Sie den größten Teil Ihrer Geschäftslogik implementieren werden, befinden sich in den Reducern. Diese können viele Formen annehmen, aber die am häufigsten verwendete Konfiguration ist eine switch-Anweisung, die jeden Fall basierend auf dem Aktionstyp behandelt. Speichern Sie dies als Reducer.js:

import * as types from './types.js' const initialState = [ { text: 'Hello World', id: 0 } ] export default function todos(state = initialState, action) { switch (action.type) { case types .ADD: return [ …state, { id: state.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1, Text: action.text } ] case Typen.DELETE: return state.filter(todo => todo.id !== action.id ) case Typen.EDIT: return state.map(todo => todo.id === action.id ? { .. .todo, text: action.text } : todo ) Standard: Rückgabezustand } }

Der Zustand wird als Argument übergeben, und jeder Fall gibt eine modifizierte Version des Zustands zurück. In diesem Beispiel hängt ADD_TODO einen neuen Artikel an den Status an (jedes Mal mit einer neuen ID), DELETE_TODO entfernt alle Artikel mit der angegebenen ID und EDIT_TODO ordnet den Text für den Artikel mit der angegebenen ID zu und ersetzt ihn.

< p>Der Anfangszustand sollte auch definiert und als Vorgabewert für die Zustandsvariable an die Reduzierfunktion übergeben werden. Dies definiert natürlich nicht Ihre gesamte Redux-Zustandsstruktur, sondern nur den Abschnitt state.todos.

Diese drei Dateien werden normalerweise in komplexeren Apps getrennt, aber wenn Sie möchten, können Sie auch definieren sie alle in einer Datei, stellen Sie nur sicher, dass Sie richtig importieren und exportieren.

Wenn diese Funktion abgeschlossen ist, schließen wir sie an Redux (und an unsere App) an. Importieren Sie in /store/root-reducer.js den todosReducer (und jeden anderen Feature-Reducer aus dem Ordner /features/) und übergeben Sie ihn dann an combineReducers(), um einen Root-Reducer der obersten Ebene zu bilden, der an den Store übergeben wird. Hier richten Sie den Root-Status ein und stellen sicher, dass jede Funktion in einem eigenen Zweig bleibt.

import {kombiniereReducers} from 'redux'; importiere todosReducer aus './features/todos/reducer'; const rootReducer = combineReducers({ todos: todosReducer }) export default rootReducer

Verwendung von Redux in React

Natürlich ist nichts davon nützlich, wenn es nicht mit React verbunden ist. Dazu müssen Sie Ihre gesamte App in eine Anbieterkomponente einschließen. Dadurch wird sichergestellt, dass der erforderliche Status und die erforderlichen Hooks an jede Komponente in Ihrer App weitergegeben werden.

Werbung

In App.js oder index.js, wo immer Sie Ihre Root-Rendering-Funktion haben, umschließen Sie Ihre App in einem <Provider> und übergeben Sie es dem Store (importiert aus /store/index.js) als Requisite:

import React from 'react”; importiere ReactDOM aus 'react-dom'; // Redux Setup import { Provider } from 'react-redux'; import store, { history } from './store'; ReactDOM.render(     <Provider store={store}> <App/>     </Provider>     , document.getElementById('root'));

Sie können Redux jetzt in Ihren Komponenten verwenden. Die einfachste Methode ist mit Funktionskomponenten und Hooks. Um beispielsweise eine Aktion zu versenden, verwenden Sie den Hook useDispatch(), mit dem Sie Aktionen direkt aufrufen können, z. Dispatch(todosActions.addTodo(text)).

Der folgende Container hat einen Eingang, der mit dem lokalen React-Status verbunden ist, der verwendet wird, um dem Status jedes Mal ein neues Todo hinzuzufügen, wenn auf eine Schaltfläche geklickt wird:

import React, { useState } from 'react'; import './Home.css'; import { TodoList } from 'components' import { todosActions } from 'store/features/todos' import { useDispatch } from 'react-redux' function Home() {   const dispatch = useDispatch(); const [text, setText] = useState(“”); function handleClick() {     dispatch(todosActions.addTodo(text)); Text setzen(“”); }   Funktion handleChange(e: React.ChangeEvent<HTMLInputElement>) {     setText(e.target.value); }   return (     <div className=”App”>       <header className=”App-header”>         <input type=”text” value={text} onChange={handle Change} /> on  .   ={handleClick}>           Neue Todo hinzufügen         </button>         <TodoList />       </header>    </div);>   } export default Startseite;

Wenn Sie dann die in state gespeicherten Daten verwenden möchten, verwenden Sie den useSelector-Hook. Dies erfordert eine Funktion, die einen Teil des Zustands zur Verwendung in der App auswählt. In diesem Fall wird die Post-Variable auf die aktuelle Liste der Aufgaben festgelegt. Dies wird dann verwendet, um für jeden Eintrag in state.todos ein neues Aufgabenelement zu rendern.

import React from 'react”; import { useSelector } from 'store' import { Container, List, ListItem, Title } from './styles' function TodoList() {   const posts = useSelector(state => state.todos)   return (     > Liste>         {posts.map(({ id, title }) => (           <ListItem key={title}>             <Title> / It ; )}       </List>     </Container>   ); } exportiere standardmäßige TodoList;

Sie können benutzerdefinierte Auswahlfunktionen erstellen, die dies für Sie erledigen, die im Ordner /features/ ähnlich wie Aktionen und Reduzierungen gespeichert werden.

Wenn Sie alles eingerichtet und herausgefunden haben, möchten Sie vielleicht Sehen Sie sich die Einrichtung von Redux Devtools, die Einrichtung von Middleware wie Redux Logger oder Connected-React-Router oder die Installation eines Nebeneffektmodells wie Redux Sagas an.