kontaktiere uns


React Native und Redux sind das Gespann, zu dem die meisten Teams greifen, wenn eine App über den lokalen Komponenten-State hinauswächst. Dieser Leitfaden zeigt, wie man beides miteinander verbindet, wie man den State über Neustarts hinweg beibehält und wie man entscheidet, ob sich dieses Muster überhaupt lohnt. Stellen Sie es sich so vor: Ohne einen Store wird der State wie ein Paket durch einen Flur von Komponente zu Komponente weitergereicht, wobei jede Komponente es nur hält, um es weiterzugeben. Redux ersetzt den Flur durch ein Lager. Ein Raum, ein Logbuch, und jeder Bildschirm kann lesen, was er braucht, ohne die Nachbarn zu belästigen.
Es gibt zwei Wege durch diese Seite. Wenn Sie die Anwendung selbst entwickeln, folgen Sie der Anleitung von oben nach unten. Wenn Sie als technischer Leiter oder Gründer entscheiden müssen, ob Sie Redux überhaupt einsetzen sollten, springen Sie direkt zum Vier-Fragen-State-Test und zum FAQ. In jedem Fall ist die zugrunde liegende Frage ebenso wirtschaftlich wie technisch: Eine vorhersehbare State-Schicht tauscht ein wenig anfänglichen Boilerplate-Code gegen eine schnellere Einarbeitung und ein geringeres Änderungsrisiko in der Zukunft ein. Der Vier-Fragen-Test hilft Ihnen dabei, festzustellen, ob sich dieser Tausch auszahlt.
Dies ist ein Leitfaden für Einsteiger zu Redux und Redux Toolkit in einer React Native-Anwendung. Er setzt voraus, dass Sie die Grundlagen von React Native beherrschen. Sind diese noch neu für Sie? Beginnen Sie mit unserem Leitfaden zu React Native und Expooder der offiziellen React Native-Dokumentationund kommen Sie dann hierher zurück.
Wir verwenden durchgehend einen Android-Emulator. Er simuliert ein Android-Gerät auf Ihrem Computer, sodass Sie Tests über verschiedene Geräte und Android-API-Level hinweg durchführen können, ohne jedes Mobiltelefon physisch besitzen zu müssen. Er bietet Ihnen fast alles, was ein echtes Gerät kann. Unser React Native und Expo-Leitfaden behandelt die Einrichtung dieser Umgebung.
Um das Ganze anschaulich zu halten, bauen wir währenddessen eine einfache Zähler-App. Sie wird in etwa so aussehen:

Hier ist der Code unserer SimpleCounter -Komponente:
// components/SimpleCounter.js
import React from 'react';
import { View, Text, Button, TextInput } from 'react-native';
const SimpleCounter = () => (
<View>
<Text>0</Text>
<Button title="-" onPress={() => {}} />
<Button title="+" onPress={() => {}} />
<TextInput keyboardType="numeric" placeholder="Amount" />
<Button title="Change by amount" onPress={() => {}} />
</View>
);
export default SimpleCounter;Im Moment ist dieser Code statisch. Es wurde noch kein State innerhalb der Komponente deklariert, und jedes folgende Beispiel baut auf diesem auf. Sobald Ihre Umgebung bereit ist, installieren Sie redux und react-redux Bibliotheken:
npm install redux react-reduxEin Hinweis zur Einrichtung: wir installieren hier das eigenständigereduxPaket, damit Sie die Funktionsweise von Grund auf nachvollziehen können. Für ein komplett neues Projekt ist das Paket, zu dem Sie eigentlich greifen sollten, Redux Toolkit,npm install @reduxjs/toolkit react-redux, das vom Redux-Team als Standard empfohlen wird. Wir arbeiten uns im weiteren Verlauf dieses Leitfadens schrittweise dorthin vor, damit Sie verstehen, welche Aufgaben es für Sie übernimmt.
Redux ist eine JavaScript-Bibliothek zur Verwaltung des Anwendungszustands. Sie bietet einen zentralen Ort, den sogenannten Store, an dem der Zustand gespeichert und über Actions und Reducer verändert wird. Man kann es sich wie ein Lagerhaus vorstellen, ergänzt um ein Protokoll, das genau festhält, wer welche Änderungen vorgenommen hat.
Dieser zentrale Ort ermöglicht es Ihnen, den Zustand zwischen verschiedenen Bildschirmen zu teilen und jederzeit nachzuvollziehen, wo und wie er verändert wird. Das macht Redux unverzichtbar für wachsende Anwendungen – also solche, die man nicht mehr vollständig überblicken kann und die genau deshalb fehleranfällig werden.
Redux verwaltet den Anwendungszustand durch eine Kombination aus Actions, Reducers und dem Store. Erfahren Sie, wie diese drei Abstraktionen zusammenwirken – der Rest ist Detailarbeit.

Der Anwendungszustand umfasst alle Informationen, die Ihre App verwendet oder verändert. Wenn Sie ihn zentralisieren und für vorhersehbare Änderungen sorgen, zeigen Ihre Bildschirme keine widersprüchlichen Informationen mehr an.
Dies ist besonders bei großen Single-Page-Anwendungen wichtig – also Apps, die einmal geladen werden und dann den Bildschirminhalt aktualisieren, anstatt bei jeder Interaktion eine neue Seite abzurufen.
Actions und Reducers verändern den Zustand gemeinsam. Actions legen fest, was und wo etwas geändert wird. Reducers bestimmen das Wie. Betrachten wir das Zähler-Layout vom Anfang dieses Beitrags, benötigen wir drei Actions: INCREMENT, DECREMENT, und CHANGE_BY_AMOUNT.
Actions sind Objekte mit einem type und einem payload Attribut. Der Typ ist der Bezeichner der Action, und das Payload enthält alles, was der Reducer benötigt, um den Zustand zu ändern. Unsere ersten beiden Actions verändern den Zähler nur um 1, daher benötigen sie nur einen Typ und sonst nichts. Die dritte benötigt ein Payload, um anzugeben, um wie viel der Wert geändert werden soll.
Deklarieren Sie Ihre Actions in einer separaten Datei namens Actions:
// redux/Actions.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const CHANGE_BY_AMOUNT = 'CHANGE_BY_AMOUNT';
export const increment = () => ({ type: INCREMENT });
export const decrement = () => ({ type: DECREMENT });
export const changeByAmount = (amount) => ({
type: CHANGE_BY_AMOUNT,
payload: { amount },
});Benennen Sie Aktionen nach dem, was passiert ist, nicht nach dem Handler, den Sie ausführen möchten. In unseren Projekten überstehen Aktionsnamen, die wie Ereignisse klingen, auch Refactorings. Namen, die wie Funktionsaufrufe klingen, werden umbenannt, sobald zwei Bildschirme dieselbe Änderung erfordern. Der Redux Styleguide führt das gleiche Argument an, falls Sie die vollständige Begründung nachlesen möchten.
Kommen wir nun zum Anfangszustand. Dieser befindet sich in einer separaten Datei neben dem Reducer:
// redux/Reducer.js
import { INCREMENT, DECREMENT, CHANGE_BY_AMOUNT } from './Actions';
const initialState = {
counter: { amount: 0 },
};Der Anfangszustand enthält ein Objekt namens counter mit einem amount Attribut, das bei 0 beginnt. Sie werden feststellen, dass es sich um eine Konstante und nicht um eine Variable handelt, was für etwas, das als Zustand beschrieben wird, ungewöhnlich erscheint. Wir kommen später darauf zurück, warum das so ist.
Nun zum Reducer, einer Funktion, die den aktuellen Zustand und die Aktion als Argumente entgegennimmt und den neuen Zustand erzeugt:
// redux/Reducer.js (continued)
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case INCREMENT:
return { ...state, counter: { amount: state.counter.amount + 1 } };
case DECREMENT:
return { ...state, counter: { amount: state.counter.amount - 1 } };
case CHANGE_BY_AMOUNT:
return {
...state,
counter: { amount: state.counter.amount + action.payload.amount },
};
default:
return state;
}
};
export default counterReducer;Wir dürfen den Zustand innerhalb eines Reducers niemals verändern. Warum nicht? Weil der Reducer das Zustandsobjekt nicht direkt modifizieren sollte; er sollte ein neues Objekt zurückgeben, das zum neuen Zustand wird. Die Rendering-Engine von React vergleicht das vorherige Zustandsobjekt mit dem neuesten, um zu entscheiden, was neu gezeichnet werden muss.
Wenn Sie den Zustand direkt ändern, erkennt React keine Änderung und hat somit eine fehlerhafte Vorstellung vom aktuellen Zustand Ihrer App. Die Redux-Dokumentation zu Mustern für unveränderliche Updates erläutert die Mechanismen im Detail.
Deshalb haben wir den Anfangszustand vorhin als Konstante deklariert. Es ist das eine Objekt im Lager, auf das niemand schreiben darf.
Als Nächstes folgt der Store selbst, das Objekt, in dem der Zustand gespeichert wird. Es ist gängige Praxis, ihn zu erstellen und aus einer eigenen Datei zu exportieren:
// redux/Store.js
import { createStore } from 'redux';
import counterReducer from './Reducer';
const store = createStore(counterReducer);
export default store;Hinweis:createStoreist seit Redux 5.0.0 offiziell als veraltet markiert, weshalb es in deinem Editor durchgestrichen dargestellt wird. Es funktioniert weiterhin und wird auch in Zukunft funktionieren, daher ist es für das Verständnis der Grundlagen hier in Ordnung. Das Redux-Team rät jedoch davon ab, es oder das eigenständigeredux-Paket direkt in neuem Code zu verwenden. Der moderne Ersatz istconfigureStoreaus dem Redux Toolkit, zu dem wir später in diesem Leitfaden kommen. Wenn du an dieser Stelle eine Warnung zur Veraltung siehst, ist das zu erwarten.
Wir erstellen den Store mit der createStore() -Methode von Redux und übergeben ihr die zuvor definierte Reducer-Funktion. Sobald der Store bereitsteht, können wir Aktionen über die dispatch-Methode auslösen – wie später in diesem Leitfaden gezeigt –, um den Status zu ändern.
Jetzt stellen wir den Store bereit, indem wir ihn an die Provider -Komponente übergeben, die SimpleCounterumschließt. Der Provider stellt den Store dieser Komponente und allen darin enthaltenen Elementen zur Verfügung.
Provider stammt aus react-redux, die offizielle Binding-Bibliothek für React und React Native mit Redux. So sieht das aus:
// App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from './redux/Store';
import SimpleCounter from './components/SimpleCounter';
const App = () => (
<Provider store={store}>
<SimpleCounter />
</Provider>
);
export default App;Jetzt verbinden wir unsere Komponenten mit dem Store. In aktuellen React Native-Codebasen erledigen Sie das mit zwei Hooks aus react-redux: useSelector liest einen Teil des States aus, und useDispatch gibt die Dispatch-Methode zurück, damit die Komponente Aktionen senden kann.
// components/SimpleCounter.js
import React, { useState } from 'react';
import { View, Text, Button, TextInput } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, changeByAmount } from '../redux/Actions';
const SimpleCounter = () => {
const amount = useSelector((state) => state.counter.amount);
const dispatch = useDispatch();
const [inputValue, setInputValue] = useState('0');
return (
<View>
<Text>{amount}</Text>
<Button title="-" onPress={() => dispatch(decrement())} />
<Button title="+" onPress={() => dispatch(increment())} />
<TextInput
keyboardType="numeric"
value={inputValue}
onChangeText={setInputValue}
/>
<Button
title="Change by amount"
onPress={() => dispatch(changeByAmount(Number(inputValue)))}
/>
</View>
);
};
export default SimpleCounter;Wir haben nur deshalb Zugriff auf das State-Objekt innerhalb von useSelector , weil SimpleCounter in den Providereingebettet ist. Der Selektor erhält den gesamten State und gibt nur den Wert zurück, den die Komponente benötigt. Dadurch wird die Komponente nur dann neu gerendert, wenn sich state.counter.amount ändert, und bleibt unverändert, wenn sich ein anderer, nicht relevanter Teil des Stores bewegt.
Halten Sie Ihre Selektoren aus diesem Grund so spezifisch wie möglich. Die häufigste Performance-Beschwerde, die wir über Redux in React Native hören, ist eine Liste, die bei jedem Tastendruck neu gerendert wird. Fast immer liegt es daran, dass ein Selektor einen ganzen Bereich oder ein frisch erstelltes Objekt zurückgibt, obwohl ein einzelner Wert ausgereicht hätte.
Ältere Codebasen verknüpfen Komponenten mit der connect -Methode und einer mapStateToProps -Funktion. Sie führt das von mapStateToProps zurückgegebene Objekt mit den Props der Komponente zusammen, sodass der gleiche Wert als this.props.amount:
// legacy pattern, still valid in existing codebases
const mapStateToProps = (state) => ({ amount: state.counter.amount });
export default connect(mapStateToProps)(SimpleCounter);Beide Ansätze greifen auf denselben Store zu. Hooks sind das empfohlene Muster für neuen Code und werden im weiteren Verlauf dieses Leitfadens verwendet. Lerne connect trotzdem kennen, da du in jedem React-Native-Projekt, das vor der Einführung von Hooks geschrieben wurde, darauf stoßen wirst.
Wir haben also einen zentralen Store, in dem der State durch Actions und Reducer vorhersehbar gespeichert und modifiziert wird. Vielleicht ist Ihnen jedoch eine Lücke aufgefallen: Schließen Sie die App und öffnen Sie sie erneut, steht der Zähler wieder auf null.
Das liegt daran, dass der State nirgendwo dauerhaft gespeichert wird. Bei jedem Start der Anwendung setzt der Reducer den Zähler auf seinen Anfangswert zurück.
Persistenz ist immer dann wichtig, wenn Informationen über eine Sitzung hinaus erhalten bleiben müssen: Login-Token, Konfigurationseinstellungen oder ein Entwurf, an dem der Nutzer gerade gearbeitet hat. In React Native erreichen Sie dies mit der redux-persist Bibliothek.
Redux Persist schreibt den Store in einen lokalen, dauerhaften Speicher und liest ihn bei jedem erneuten Öffnen oder Aktualisieren der App wieder ein. Wir verwenden hier einen Android-Emulator, aber es funktioniert genauso problemlos unter iOS. Beginnen Sie mit der Installation, zusammen mit AsyncStorage, dem Key-Value-Speicher, in den geschrieben wird:
npm install redux-persist @react-native-async-storage/async-storageÄndern Sie anschließend die Store.js Datei wie folgt:
// redux/Store.js
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
import counterReducer from './Reducer';
const persistConfig = {
key: 'root',
storage: AsyncStorage,
};
const persistedReducer = persistReducer(persistConfig, counterReducer);
export const store = createStore(persistedReducer);
export const persistor = persistStore(store);Importieren Sie persistStore und persistReducer aus redux-persist. Übergeben Sie Ihren Reducer an persistReducer zusammen mit dem persistConfig -Objekt, und Sie erhalten einen persistedReducer zurück.
Im persistConfig legen Sie fest, dass AsyncStorage den Store aufnehmen soll. AsyncStorage ist der Key-Value-Speicher von React Native und unverschlüsselt. Daher gehören sensible Daten, insbesondere Authentifizierungs-Token, stattdessen in einen sicheren Speicher.

Rufen Sie abschließend persistStore auf, um den Store persistent zu halten. Bei größeren Projekten möchten Sie möglicherweise nicht den gesamten Status auf die Festplatte schreiben; genau dafür sind die Optionen whitelist und blacklist in persistConfig gedacht: Wählen Sie die Reducer aus, die gespeichert werden sollen, und lassen Sie den Rest weg. Die redux-persist README dokumentiert beides.
Zuletzt importieren Sie in der App.jsden persistor von Store.js und umschließen Sie SimpleCounter mit PersistGate. Es hält die Benutzeroberfläche zurück, bis der gespeicherte Zustand abgerufen und in den Store geladen wurde. So sehen Benutzer niemals den anfänglichen Zustand aufblitzen, bevor der tatsächliche Zustand geladen ist:
// App.js
import React from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from './redux/Store';
import SimpleCounter from './components/SimpleCounter';
const App = () => (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<SimpleCounter />
</PersistGate>
</Provider>
);
export default App;Redux Toolkit ist eine von den Redux-Entwicklern geschriebene Bibliothek, die Ihnen hilft, effizientere Redux-Logik zu erstellen. Sie ist die Empfehlung des Redux-Teams für neue Projekte und ersetzt den Großteil des obigen Codes durch einen Bruchteil davon.
Sie ist zudem der Standard im Ökosystem: Redux Toolkit ist die offizielle Empfehlung des Redux-Teams für alle neuen Projekte, und die große Mehrheit der React-Redux-Installationen nutzt es mittlerweile, anstatt Redux manuell zu implementieren. Wir setzen es auch in der Produktion ein. TrustPortal basiert auf Redux Toolkit, um den State in einer großen Unternehmensanwendung vorhersehbar zu halten – genau der Vorteil, der hier beschrieben wird. Im Folgenden finden Sie einen Überblick über die wichtigsten Funktionen.
createAction() zum Deklarieren von ActionsRedux Toolkit bietet uns eine neue Möglichkeit, eine Action zu erstellen:
import { createAction } from '@reduxjs/toolkit';
export const increment = createAction('INCREMENT');
export const decrement = createAction('DECREMENT');
export const changeByAmount = createAction('CHANGE_BY_AMOUNT');createAction nimmt den Action-Typ als Argument entgegen und gibt eine Action-Creator-Funktion zurück. Rufen Sie diese Funktion auf, übergeben Sie das Payload, und Sie erhalten das Action-Objekt. Sie können den Typ auch über die toString() Methode auslesen, wie bei increment.toString(). Das Deklarieren von Action-Typen als Konstanten entfällt, was den Boilerplate-Code erheblich reduziert.
createReducer() zum Schreiben von ReducerncreateReducer vereinfacht die andere Hälfte. Anstatt einer Switch-Anweisung ordnen Sie jede Action der Funktion zu, die sie verarbeitet. Das ist wesentlich übersichtlicher, und die von createAction() kann direkt an addCase()übergeben werden. Mit der gleichen Reducer-Logik wie zuvor:
import { createReducer } from '@reduxjs/toolkit';
import { increment, decrement, changeByAmount } from './Actions';
const initialState = { counter: { amount: 0 } };
const counterReducer = createReducer(initialState, (builder) => {
builder
.addCase(increment, (state) => ({
...state,
counter: { amount: state.counter.amount + 1 },
}))
.addCase(decrement, (state) => ({
...state,
counter: { amount: state.counter.amount - 1 },
}))
.addCase(changeByAmount, (state, action) => ({
...state,
counter: { amount: state.counter.amount + action.payload },
}));
});createReducer() verwendet ebenfalls Immer, eine Bibliothek, mit der Sie Code schreiben können, der so aussieht, als würde er den State verändern, während er im Hintergrund stillschweigend eine neue Kopie erstellt. Immer übersetzt jeden verändernden Vorgang in die entsprechende Kopieroperation. Das bedeutet, wir können den Reducer so schreiben:
const counterReducer = createReducer(initialState, (builder) => {
builder
.addCase(increment, (state) => {
state.counter.amount += 1;
})
.addCase(decrement, (state) => {
state.counter.amount -= 1;
})
.addCase(changeByAmount, (state, action) => {
state.counter.amount += action.payload;
});
});Deutlich kürzer. Gleiches Verhalten.
createSlice() für Actions und Reducer zusammenIn der Praxis rufen Sie createAction und createReducer nur selten separat auf. createSlice generiert beides aus einer einzigen Definition: Benennen Sie den Slice, geben Sie einen Initialzustand sowie eine Reihe von Reducer-Funktionen an, und Sie erhalten den Reducer sowie für jede Funktion den passenden Action Creator zurück.
// redux/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { amount: 0 },
reducers: {
increment: (state) => {
state.amount += 1;
},
decrement: (state) => {
state.amount -= 1;
},
changeByAmount: (state, action) => {
state.amount += action.payload;
},
},
});
export const { increment, decrement, changeByAmount } = counterSlice.actions;
export default counterSlice.reducer;Die gesamte Actions.js und Reducer.js Paar von vorhin wird in dieser einen Datei zusammengefasst. Ihre Komponenten verwenden weiterhin useSelector und useDispatch genau wie bisher.
configureStore() zum Erstellen des StoresconfigureStore() umschließt createStore() und richtet dabei sinnvolle Standardeinstellungen ein, einschließlich der Redux DevTools-Verbindung und der Standard-Middleware, also der Funktionen, die jede Aktion auf ihrem Weg zum Reducer durchläuft. Da es der moderne Nachfolger des mittlerweile als veraltet geltenden createStoreist, sollten Sie bei jedem neuen Projekt darauf zurückgreifen.
Es akzeptiert zudem ein Konfigurationsobjekt anstelle einer Gruppe von Funktionen, sodass der Reducer innerhalb eines Objekts unter dem reducer Attribut platziert wird:
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
export const store = configureStore({
reducer: { counter: counterReducer },
});Wenn Sie redux-persist und Redux Toolkit im selben Projekt verwenden, werden Sie früher oder später auf den Fehler 'A non-serializable value was detected in an action' stoßen. Die Ursache: configureStore() führt eine Serialisierbarkeitsprüfung durch – eine Schutzmaßnahme während der Entwicklung, die warnt, wenn eine Aktion Elemente enthält, die Redux nicht sicher speichern kann, wie etwa Funktionen oder Promises. Da redux-persist jedoch Funktionen innerhalb seiner eigenen Aktionen weitergeben muss, kommt es hier zu Konflikten.
Die Lösung besteht darin, die Prüfung beizubehalten, aber die Aktionstypen von redux-persist davon auszunehmen:
import { configureStore } from '@reduxjs/toolkit';
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
import counterReducer from './counterSlice';
const persistConfig = { key: 'root', storage: AsyncStorage };
const persistedReducer = persistReducer(persistConfig, counterReducer);
export const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}),
});
export const persistor = persistStore(store);Beachten Sie den Unterschied zwischen dem Ausnehmen dieser sechs Aktionstypen und dem vollständigen Deaktivieren der Prüfung. Schalten Sie diese komplett ab, verlieren Sie die Warnung für jeden tatsächlich nicht serialisierbaren Wert, den Ihr eigener Code in den Store schreibt. Die Diskussion sowie die Lösung finden Sie im redux-persist Issue zur Serialisierbarkeitsprüfung.
createAsyncThunk und RTK QueryUnser Zähler ist synchron. Fast keine echte App ist das. Unserer Erfahrung nach ist das Abrufen von Daten der häufigste Grund, warum ein React Native-Team überhaupt auf Redux umsteigt: Eine Anfrage hat einen Ladezustand, einen Erfolgszustand und einen Fehlerzustand. Mehrere Bildschirme benötigen alle drei, und das Weiterreichen als Props funktioniert schnell nicht mehr.
Redux Toolkit bietet zwei Antworten, und die Wahl zwischen ihnen ist die praktische Entscheidung, vor der die meisten Teams stehen.
createAsyncThunk umschließt ein Promise und sendet in Ihrem Namen drei Aktionen, eine pro Phase, die Sie in extraReducersverarbeiten:
// redux/counterSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
export const fetchCounter = createAsyncThunk(
'counter/fetch',
async (userId) => {
const response = await fetch(`https://api.example.com/counter/${userId}`);
return response.json();
},
);
const counterSlice = createSlice({
name: 'counter',
initialState: { amount: 0, status: 'idle', error: null },
reducers: {
increment: (state) => {
state.amount += 1;
},
},
extraReducers: (builder) => {
builder
.addCase(fetchCounter.pending, (state) => {
state.status = 'loading';
})
.addCase(fetchCounter.fulfilled, (state, action) => {
state.status = 'succeeded';
state.amount = action.payload.amount;
})
.addCase(fetchCounter.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message;
});
},
});Die Komponente sendet den Thunk ab und liest den Status:
const dispatch = useDispatch();
const { amount, status } = useSelector((state) => state.counter);
useEffect(() => {
if (status === 'idle') dispatch(fetchCounter(userId));
}, [status, dispatch, userId]);RTK Query geht noch weiter. Definieren Sie Ihre Endpunkte und es generiert die Thunks, die Reducer, den Cache und einen Hook pro Endpunkt, sodass die gesamte Lade- und Fehlerbehandlung im Hook verschwindet:
// redux/api.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.example.com/' }),
endpoints: (builder) => ({
getCounter: builder.query({ query: (userId) => `counter/${userId}` }),
}),
});
export const { useGetCounterQuery } = api;
const { data, isLoading, error } = useGetCounterQuery(userId);Welches sollten Sie also wählen? Verwenden Sie createAsyncThunk , wenn die asynchrone Arbeit ein Seiteneffekt ist, den Sie selbst steuern, wie etwa ein Anmeldevorgang oder eine Hintergrundsynchronisierung. Verwenden Sie RTK Query, wenn Sie Serverdaten zwischenspeichern – was auf Mobilgeräten meistens der Fall ist –, da Caching, erneutes Abrufen und Invalidierung genau die Bereiche sind, die Teams bei manueller Umsetzung oft falsch machen. Mark Erikson, ein Redux-Maintainer, erklärt in diesem Artikel über RTK und asynchrone Logik, warum Thunks das Standardwerkzeug für asynchrone Aufgaben sind.
Unser Leitfaden zum Thema Umgang mit asynchronen Operationen in Redux befasst sich eingehend mit Thunks, Sagas und den Middleware-Alternativen. Für ein produktionsreifes Beispiel zum gleichen Problem von Laden, Caching und erneutem Abrufen, Confinze kombiniert Redux mit React Query in einem Fintech-Produkt und erreichte dank dieser Vorhersehbarkeit eine Kundenbindungsrate von 85 %.
Redux ist nicht kostenlos. Es fügt Dateien, Indirektion und ein Muster hinzu, das jedes Teammitglied erst erlernen muss. Bevor wir es in einem Projekt einsetzen, führen wir den Vier-Fragen-Test durch, und die Antworten klären die Sache meistens:
useState ist das richtige Werkzeug.
Bei zwei oder mehr Ja-Antworten lohnt sich Redux. Bei einer oder keiner Antwort sind Reacts eigener State und Context die bessere und effizientere Wahl.
Wir haben beide Wege beschritten. Ein internes Tool mit nur einem Bildschirm und einem Entwickler blieb bei useState und war dadurch schneller fertig. Eine Liefer-App mit Offline-Entwürfen, Push-Updates und einem wechselnden Team wurde auf Redux Toolkit umgestellt, genau deshalb, weil State-Fehler ständig aus drei Richtungen gleichzeitig auftraten. Bei AppTweaktrug ein diszipliniertes State-Management in einem datenintensiven Dashboard dazu bei, die Ladezeit um 80 % zu senken – und genau das ist der Nutzen, den dieser Test abwägt.
Die wirtschaftliche Betrachtungsweise gilt in beiden Fällen. Sie wägen einmalige, geringe Einrichtungskosten gegen die Kosten späterer Änderungen ab: wie schnell ein neuer Entwickler produktiv wird, wie sicher Sie Funktionen bereitstellen können, die auf gemeinsam genutzte Daten zugreifen, und wie viel Ihres Budgets in die Fehlerbehebung statt in die Entwicklung fließt. Weitere Ergebnisse finden Sie in unseren Fallstudien.
Nicht immer. Seit der Einführung von Hooks und Context verwalten viele Apps ihren gemeinsamen Status auch ohne Redux. Redux ist jedoch weiterhin sinnvoll, wenn der Status von verschiedenen Bildschirmen aus gelesen und geschrieben wird, einen Neustart überdauern muss oder von einem Team statt von einer einzelnen Person gepflegt wird. Für einen einzelnen Bildschirm mit lokalem Status ist useState völlig ausreichend.
Sie lösen unterschiedliche Probleme. Context reicht einen Wert durch den Komponentenbaum weiter und rendert jeden Consumer neu, sobald sich der Wert ändert – was für Themes oder Sprachlokalisierungen völlig in Ordnung ist. Redux Toolkit bietet hingegen vorhersagbare Updates, selektives Re-Rendering durch Selektoren, Time-Travel-Debugging mit den DevTools und einen fest definierten Ort für jede Statusänderung. Verwenden Sie Context für Werte, die sich selten ändern oder ein geringes Volumen haben, und Redux Toolkit für Statusdaten, die häufig aktualisiert werden oder aus verschiedenen Quellen stammen.
Installieren Sie redux-persist und AsyncStorage, umschließen Sie Ihren Reducer mit persistReducer sowie einer persistConfig, erstellen Sie den Persistor mit persistStoreund umschließen Sie anschließend Ihre App mit PersistGate , damit die Benutzeroberfläche auf den geladenen Status wartet. Nutzen Sie die Optionen „whitelist“ und „blacklist“, um nur die benötigten Statusbereiche zu speichern, und bewahren Sie Tokens in einem sicheren Speicher auf, anstatt in AsyncStorage, da dieser unverschlüsselt ist.
Dieser Fehler wird von configureStore's Serialisierbarkeitsprüfung mit den eigenen Aktionen von redux-persist. Übergeben Sie eine Middleware-Option an configureStore und fügen Sie FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE sowie REGISTER zu ignoredActionshinzu. Deaktivieren Sie die Prüfung nicht vollständig, da Sie sonst die Warnungen für tatsächlich nicht serialisierbare Werte in Ihrem eigenen Code verlieren.
createAsyncThunk oder RTK Query für API-Aufrufe verwenden?RTK Query für Serverdaten, die zwischengespeichert, neu geladen und invalidiert werden sollen – das deckt die meisten mobilen Bildschirme ab. createAsyncThunk für Seiteneffekte, die Sie vollständig selbst steuern, wie etwa einen Login-Prozess oder einen Synchronisierungsauftrag. Beides ist in Redux Toolkit enthalten, sodass die Entscheidung je nach Anwendungsfall und nicht pro Projekt getroffen wird.
Oft ja. Wenn die App nur wenige Bildschirme hat, von einem einzelnen Entwickler betreut wird und keinen Status besitzt, der über eine Sitzung hinausgeht, ist der Aufwand für den Boilerplate-Code größer als der Nutzen. Führen Sie den oben genannten Vier-Fragen-Test durch: Bei weniger als zwei Ja-Antworten sind Sie mit useState und Context besser beraten.
createStoreverwenden oder reicht Redux Toolkit aus?Redux Toolkit reicht aus und wird vom Redux-Team für neue Projekte empfohlen. Die Kernfunktion createStore ist mittlerweile veraltet. configureStore, createSlice und Immer ersetzen die manuellen Aktionskonstanten, Switch-Statement-Reducer und die Store-Konfiguration, die zuvor in diesem Leitfaden gezeigt wurden. Die ausführliche Form ist dennoch einmal lesenswert, da sie verdeutlicht, was das Toolkit für Sie erledigt, und sie ist das, was Sie in älteren Codebasen vorfinden werden.
Actions beschreiben, was passiert ist, Reducer legen fest, wie sich der State ändert, und der Store speichert das Ergebnis, sodass jeder Screen darauf zugreifen kann. Das Redux Toolkit eliminiert den Großteil des Boilerplate-Codes, RTK Query kümmert sich um Serverdaten, redux-persist erhält den State über Neustarts hinweg, und der Vier-Fragen-Test für State-Management zeigt Ihnen, ob sich der Einsatz lohnt. Da Redux view-agnostisch ist, lässt sich all dies problemlos auf React-Webanwendungen übertragen.
Sie wägen das State-Management für ein mobiles Produkt ab oder haben eine App übernommen, bei der der State zum Flaschenhals geworden ist? Unser Team arbeitet täglich an solchen Herausforderungen. Werfen Sie einen Blick auf unsere Entwicklungsleistungen, oder erzählen Sie uns von Ihrem Projekt und wir sagen Ihnen ehrlich, ob Redux die richtige Wahl dafür ist.


Informatikstudent und Teilzeitbeschäftigter von Imaginary Cloud. Begierig darauf, neue Technologien und Techniken zu erlernen. Tennis- und Klavierspieler.

Alexandra Mendes ist Senior Growth Specialist bei Imaginary Cloud und verfügt über mehr als 3 Jahre Erfahrung in der Erstellung von Texten über Softwareentwicklung, KI und digitale Transformation. Nach Abschluss eines Frontend-Entwicklungskurses erwarb Alexandra einige praktische Programmierkenntnisse und arbeitet nun eng mit technischen Teams zusammen. Alexandra ist begeistert davon, wie neue Technologien Wirtschaft und Gesellschaft prägen. Sie liebt es, komplexe Themen in klare, hilfreiche Inhalte für Entscheidungsträger umzuwandeln.
People who read this post, also found these interesting: