Boilerplate, Performance und Persistenz in React-Native-Apps
Die Wahl des State-Management-Ansatzes entscheidet in React-Native-Apps über Boilerplate-Umfang, Re-Render-Verhalten und Wartbarkeit. Zustand und Redux Toolkit lösen dasselbe Grundproblem mit unterschiedlicher Philosophie: minimaler Hooks-basierter Store gegen strukturiertes, batteriebetriebenes Redux-Ökosystem mit DevTools, RTK Query und etabliertem Tooling.
Inhaltsverzeichnis
- 1. Warum die Wahl des State-Management-Ansatzes wichtig ist
- 2. Zustand: Setup und Grundprinzip
- 3. Redux Toolkit: Setup und Grundprinzip
- 4. Asynchrone Aktionen und Side Effects
- 5. Persistenz von State über App-Neustarts
- 6. DevTools und Debugging beider Ansätze
- 7. Performance und Re-Renders
- 8. Testing von Stores und Slices
- 9. Zustand vs. Redux Toolkit im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum die Wahl des State-Management-Ansatzes wichtig ist
Klassisches Redux verlangte für jede State-Änderung Action-Types, Action-Creator, Reducer und manuelles Dispatch-Wiring, bevor überhaupt eine Zeile fachlicher Logik geschrieben war. Redux Toolkit hat diesen Boilerplate mit createSlice und Immer-basierten Reducern drastisch reduziert, bleibt aber strukturell aufwendiger als ein minimaler Hooks-Store. Bei State Management in React-Native-Projekten mit knappem Zeitbudget summiert sich dieser Unterschied schnell über Dutzende Slices und Screens hinweg.
Auf mobilen Geräten kosten unnötige Re-Renders spürbar mehr als im Browser: Jede Aktualisierung durchläuft die Bridge beziehungsweise die neue Fabric-Architektur, bevor sie in nativen Views ankommt, und blockiert währenddessen den JS-Thread. Ein State-Management-Ansatz ohne granulare Subscriptions lässt ganze Komponentenbäume neu rendern, sobald sich irgendein Teil des globalen Zustands ändert, was während Scroll- oder Gestensteuerung zu spürbaren Frame-Drops führt. Genau hier unterscheiden sich Zustand und Redux Toolkit in der Praxis, obwohl beide selektive Subscriptions technisch anbieten.
Die beiden dominierenden Antworten auf diese Frage sind heute Zustand, ein minimalistischer, hooks-basierter Store ohne Provider-Zwang, und Redux Toolkit, die offizielle, batteriebetriebene Weiterentwicklung von Redux mit RTK Query, Entity-Adaptern und ausgereiften DevTools. Beide lösen State Management für React-Native-Apps zuverlässig, unterscheiden sich aber deutlich in Boilerplate, Lernkurve und Ökosystem-Tiefe, was die folgenden Abschnitte im Detail zeigen.
2. Zustand: Setup und Grundprinzip
Zustand reduziert State Management auf eine einzige Funktion: create() erzeugt einen Hook, der sowohl den aktuellen State als auch die Aktionen zu seiner Veränderung bereitstellt. Es gibt keinen verpflichtenden Provider, keine Context-Verschachtelung und keine Trennung zwischen Action-Type-Konstanten und Reducer-Funktionen. Ein Store ist ein Plain-JavaScript-Objekt mit set und get, das per Closure Zugriff auf sich selbst hat.
Die Installation ist minimal, ein einzelnes Package ohne Peer-Dependencies auf React-Context-Interna. Komponenten abonnieren Zustand-Stores über denselben Hook, der auch den Store erzeugt hat, wobei eine Selector-Funktion als Argument bestimmt, welcher Slice des States die Komponente überhaupt betrifft. Ändert sich ein anderer Teil des Stores, rendert die Komponente nicht neu, weil Zustand intern nur den zurückgegebenen Wert per Referenzvergleich prüft.
Dieses Grundprinzip macht Zustand besonders attraktiv für kleinere bis mittelgroße React-Native-Apps, in denen der Ceremony-Aufwand von Redux Toolkit in keinem Verhältnis zur tatsächlichen State-Komplexität steht. Mehrere unabhängige Stores lassen sich parallel anlegen, etwa ein Auth-Store und ein Cart-Store, ohne dass ein zentraler Root-Reducer beide zusammenführen muss.
# Install Zustand: single package, no extra peer dependencies
npm install zustand
# Optional: persist middleware needs AsyncStorage as the storage adapter
npm install @react-native-async-storage/async-storage
// store/useCartStore.js
import { create } from 'zustand';
// A Zustand store is just a hook created by create()
export const useCartStore = create((set, get) => ({
items: [],
addItem: (product) =>
set((state) => ({ items: [...state.items, product] })),
removeItem: (id) =>
set((state) => ({ items: state.items.filter((i) => i.id !== id) })),
clear: () => set({ items: [] }),
// Derived value computed from current state via get()
total: () => get().items.reduce((sum, i) => sum + i.price, 0),
}));
// Component: subscribe only to the slice this component actually needs
function CartBadge() {
const itemCount = useCartStore((state) => state.items.length);
return <Text>Cart: {itemCount}</Text>;
}
3. Redux Toolkit: Setup und Grundprinzip
Redux Toolkit baut auf klassischem Redux auf, verpackt aber die drei früher getrennten Konzepte, Action-Types, Action-Creator und Reducer, in einer einzigen createSlice-Definition. Intern nutzt createSlice Immer, wodurch Reducer-Funktionen scheinbar mutierenden Code schreiben dürfen, obwohl im Hintergrund weiterhin ein neuer, immutabler State erzeugt wird. Das senkt die Fehleranfälligkeit gegenüber handgeschriebenem Redux erheblich, ohne das Grundprinzip von Redux aufzugeben.
Der Store selbst entsteht über configureStore, das sinnvolle Defaults wie Redux-Thunk-Middleware und Redux-DevTools-Anbindung automatisch aktiviert. Anders als bei Zustand braucht jede Redux-Toolkit-App einen Provider-Wrapper um die Root-Komponente, der den Store per Context an die gesamte Komponentenhierarchie weiterreicht. Diese zentrale Struktur erzwingt einen einheitlichen State-Baum, was bei großen Teams und vielen parallelen Feature-Branches Konsistenz erleichtert.
Für State Management in umfangreichen React-Native-Apps mit mehreren Domänen, etwa Auth, Katalog, Warenkorb und Checkout, bringt Redux Toolkit mit Entity-Adaptern, Selektoren und einem klaren Konventionsrahmen Struktur, die bei rein hooks-basierten Ansätzen selbst diszipliniert nachgebaut werden müsste.
// store/cartSlice.js
import { createSlice, configureStore } from '@reduxjs/toolkit';
const cartSlice = createSlice({
name: 'cart',
initialState: { items: [] },
reducers: {
// Immer lets us write "mutating" code, it produces an immutable update under the hood
addItem: (state, action) => {
state.items.push(action.payload);
},
removeItem: (state, action) => {
state.items = state.items.filter((i) => i.id !== action.payload);
},
clear: (state) => {
state.items = [];
},
},
});
export const { addItem, removeItem, clear } = cartSlice.actions;
// configureStore enables Redux DevTools and thunk middleware by default
export const store = configureStore({
reducer: { cart: cartSlice.reducer },
});
// App root: Provider makes the store available via React context
// <Provider store={store}><App /></Provider>
4. Asynchrone Aktionen und Side Effects
Bei Zustand gibt es keinen eigenen Mechanismus für asynchrone Aktionen, weil keiner nötig ist: Eine Store-Aktion kann einfach eine async-Funktion sein, die vor dem finalen set()-Aufruf auf ein Promise wartet. Zwischenzustände wie loading oder error werden als normale State-Felder geführt und über zusätzliche set()-Aufrufe vor und nach dem Await gesetzt. Für einfache API-Aufrufe ist das State Management damit denkbar direkt, ohne Middleware, ohne zusätzliche Konzepte.
Redux Toolkit bietet mit createAsyncThunk ein strukturiertes Muster: Der Thunk kapselt den asynchronen Aufruf, und drei automatisch generierte Action-Types, pending, fulfilled und rejected, lassen sich in extraReducers gezielt behandeln. Für datenintensive Apps geht RTK Query noch einen Schritt weiter und übernimmt Caching, Deduplizierung paralleler Requests und automatische Invalidierung nach Mutationen, ohne dass eigene Loading-Flags manuell verwaltet werden müssen.
Der praktische Unterschied zeigt sich bei Skalierung: Ein einzelner API-Aufruf ist bei Zustand in drei Zeilen erledigt, während Redux Toolkit mit einem zusätzlichen Thunk-Setup startet. Sobald aber Dutzende Endpunkte mit Caching, Refetching bei Reconnect und optimistischen Updates zusammenkommen, kehrt sich der Aufwand um, weil RTK Query genau diese Fälle bereits vorgedacht hat.
5. Persistenz von State über App-Neustarts
Für Zustand genügt die persist-Middleware aus zustand/middleware, die den Store beim Erzeugen mit einem Storage-Adapter verbindet. In React Native übernimmt @react-native-async-storage/async-storage diese Rolle, weil localStorage auf dem Gerät nicht existiert. Mit partialize lässt sich gezielt festlegen, welche Felder überhaupt persistiert werden, etwa Auth-Tokens, aber keine flüchtigen UI-Flags.
Redux Toolkit nutzt für Persistenz klassischerweise redux-persist: Der Root-Reducer wird mit persistReducer umschlossen, ein persistStore-Objekt wird zusätzlich erzeugt, und die App-Root wird mit einer PersistGate-Komponente umgeben, die das Rendering verzögert, bis der gespeicherte State geladen ist. Dieses Setup ist umfangreicher als bei Zustand, dafür aber granular konfigurierbar über Whitelists und Blacklists pro Slice.
Beide Ansätze lösen State Management über App-Neustarts hinweg zuverlässig, unterscheiden sich aber im Ceremony-Aufwand: Zustand braucht eine einzelne Middleware-Funktion, Redux Toolkit einen zusätzlichen Provider und eine Wrapper-Komponente. Für Apps mit vielen Slices und unterschiedlichen Persistenz-Strategien pro Domäne bietet redux-persist mehr eingebaute Konfigurationsoptionen.
{
"persistConfig": {
"name": "app-storage",
"storage": "AsyncStorage",
"partialize": ["auth", "cartItems"],
"version": 1
},
"dependencies": {
"zustand": "^5.0.0",
"@react-native-async-storage/async-storage": "^1.23.1",
"@reduxjs/toolkit": "^2.2.0",
"redux-persist": "^6.0.0",
"react-redux": "^9.1.0"
}
}
6. DevTools und Debugging beider Ansätze
Für Redux Toolkit ist die Anbindung an die Redux DevTools per configureStore standardmäßig aktiv, ganz ohne zusätzliche Konfiguration. Time-Travel-Debugging, Action-Replay und ein vollständiger Verlauf aller dispatchten Actions gehören zum Standardumfang, und über redux-flipper lässt sich derselbe Action-Log auch direkt in Flipper innerhalb der React-Native-Entwicklungsumgebung anzeigen.
Zustand bietet mit der devtools-Middleware aus zustand/middleware eine Anbindung an dasselbe Redux-DevTools-Protokoll, wodurch auch Zustand-Änderungen im vertrauten DevTools-Panel erscheinen. Die Middleware ist jedoch optional und muss pro Store explizit aktiviert werden, während sie bei Redux Toolkit implizit für den gesamten Store gilt. Die Flipper-Integration für Zustand ist weniger etabliert als für Redux Toolkit und erfordert meist eine eigene kleine Bridge-Konfiguration.
7. Performance und Re-Renders
Bei Zustand verhindert die Selector-Funktion im Hook-Aufruf unnötige Re-Renders bereits im Grundfall, weil nur der zurückgegebene Wert per Referenzvergleich geprüft wird. Werden mehrere Felder gleichzeitig selektiert, etwa { name, email }, entsteht bei jedem Aufruf ein neues Objekt, was den Referenzvergleich immer fehlschlagen lässt. Die Lösung ist zustand/shallow als zweites Argument, das die Felder flach vergleicht statt per Referenzidentität.
Redux Toolkit setzt für dasselbe Problem auf memoisierte Selektoren mit createSelector aus Reselect, das automatisch im Toolkit enthalten ist. Bei Listen mit vielen Einträgen verhindert createEntityAdapter zusätzlich, dass jede kleine Änderung an einem Eintrag den gesamten Array-Reducer neu durchlaufen lässt, weil der State intern als normalisiertes Dictionary mit IDs geführt wird statt als Array.
In beiden Welten gilt dieselbe Grundregel für State Management auf mobilen Geräten: Ein useStore() oder useSelector() ohne Selector-Funktion abonniert den kompletten Store und macht jede noch so kleine Änderung zum Auslöser für ein Re-Render der Komponente. Diszipliniertes Selector-Design ist bei beiden Bibliotheken die wichtigste Stellschraube für flüssige Scroll- und Listen-Performance.
8. Testing von Stores und Slices
Ein Zustand-Store ist im Kern ein Plain-JavaScript-Objekt mit getState() und setState(), weshalb Tests ohne Provider-Mocking und ohne Rendering einer Komponente auskommen. Vor jedem Test lässt sich der Store einfach mit useCartStore.setState(initialState, true) zurücksetzen, der zweite Parameter ersetzt dabei den kompletten State statt ihn nur zu mergen.
Ein Redux Toolkit-Slice-Reducer ist eine pure Funktion, die einen State und eine Action entgegennimmt und einen neuen State zurückgibt, weshalb Unit-Tests ganz ohne Store-Setup mit einfachen Action-Objekten auskommen. Für Integrationstests, die mehrere Slices zusammen prüfen, wird zusätzlich eine configureStore-Instanz mit den zu testenden Reducern erzeugt.
Beide Ansätze machen State Management gut testbar, weil die eigentliche Logik in beiden Fällen von der UI entkoppelt ist. Der Unterschied liegt im Umfang der Testinfrastruktur: Zustand-Tests brauchen fast keine Vorbereitung, Redux-Toolkit-Tests profitieren von der klaren Trennung zwischen reinen Reducern und Thunk-Logik, die separat gemockt werden kann.
// __tests__/cartStore.test.js
import { useCartStore } from '../store/useCartStore';
describe('cart store', () => {
beforeEach(() => {
// Replace full state before every test, no Provider needed
useCartStore.setState({ items: [] }, true);
});
test('addItem appends a product', () => {
useCartStore.getState().addItem({ id: 1, price: 9.99 });
expect(useCartStore.getState().items).toHaveLength(1);
});
test('total sums item prices', () => {
useCartStore.getState().addItem({ id: 1, price: 9.99 });
useCartStore.getState().addItem({ id: 2, price: 5.0 });
expect(useCartStore.getState().total()).toBeCloseTo(14.99);
});
});
9. Zustand vs. Redux Toolkit im direkten Vergleich
Die folgende Tabelle fasst die wichtigsten Unterschiede zwischen Zustand und Redux Toolkit für State Management in React-Native-Apps zusammen. Keine der beiden Bibliotheken ist grundsätzlich überlegen, die richtige Wahl hängt von Projektgröße, Team-Konventionen und dem Bedarf an eingebauten Zusatzfunktionen wie RTK Query ab.
| Kriterium | Zustand | Redux Toolkit |
|---|---|---|
| Boilerplate | Minimal, ein create()-Aufruf pro Store |
Gering dank createSlice, aber mehr Struktur nötig |
| Bundle-Größe | Sehr klein, wenige KB gzipped | Größer durch Redux-Kern, Toolkit und Immer |
| Lernkurve | Flach, im Wesentlichen nur Hooks-Wissen nötig | Steiler, Redux-Konzepte wie Reducer und Actions nötig |
| DevTools | Optional per Middleware, weniger ausgereift | Standardmäßig aktiv, Time-Travel-Debugging |
| Async-Handling | Einfache async-Funktionen im Store |
createAsyncThunk oder RTK Query mit Caching |
| Persistenz | zustand/middleware persist, wenig Setup |
redux-persist, mehr Konfiguration, mehr Kontrolle |
In der Praxis entscheidet oft die Team-Erfahrung: Teams mit Redux-Hintergrund profitieren vom strukturierten Rahmen von Redux Toolkit und dessen Ökosystem, während Teams, die State Management so schlank wie möglich halten wollen, mit Zustand schneller produktiv sind. Beide Bibliotheken lassen sich zudem in derselben App parallel einsetzen, etwa Zustand für lokalen UI-State und Redux Toolkit für serverseitig synchronisierte Domänendaten über RTK Query.
10. Zusammenfassung
State Management in React-Native-Apps ist keine reine Geschmacksfrage, sondern hat direkte Auswirkungen auf Bundle-Größe, Re-Render-Verhalten und Entwicklungsgeschwindigkeit. Zustand punktet mit minimalem Boilerplate, flacher Lernkurve und einer Store-Definition, die ohne Provider und ohne Redux-Vokabular auskommt. Redux Toolkit bringt dafür ein etabliertes Ökosystem mit, standardmäßig aktive DevTools, RTK Query für serverseitige Daten und Entity-Adapter für normalisierte Listen.
Für neue, überschaubare Apps ist Zustand häufig der pragmatischere Einstieg in State Management, weil der Ceremony-Aufwand von Redux Toolkit erst bei wachsender Komplexität seinen vollen Nutzen entfaltet. Große Teams mit vielen parallelen Feature-Branches, komplexem Server-State und dem Bedarf an Time-Travel-Debugging fahren dagegen oft besser mit der Struktur und Reife von Redux Toolkit. Die Tabelle in Abschnitt 9 liefert die Entscheidungsgrundlage für die konkrete Projektsituation.
Zustand vs. Redux Toolkit: Das Wichtigste auf einen Blick
Boilerplate
Zustand kommt mit einem einzigen create()-Aufruf aus, Redux Toolkit strukturiert über createSlice und configureStore.
Async & Persistenz
Zustand nutzt einfache async-Funktionen und die persist-Middleware. Redux Toolkit setzt auf createAsyncThunk, RTK Query und redux-persist.
DevTools
Redux Toolkit aktiviert Redux DevTools standardmäßig. Zustand braucht dafür die optionale devtools-Middleware.
Performance
Beide brauchen diszipliniertes Selector-Design: zustand/shallow bei Zustand, createSelector und Entity-Adapter bei Redux Toolkit.