Redux — przewidywalny kontener do zarządzania stanem dla aplikacji JavaScript, stworzony przez Dana Abramova w 2015 roku. Redux implementuje jednokierunkowy przepływ danych oparty na architekturze Flux: stan przechowywany jest w pojedynczym Store, zmieniany tylko przez czyste funkcje Reducer i inicjowany przez Action z Dispatch. Według danych npm Trends, Redux utrzymuje ponad 7 milionów tygodniowych pobrań, pozostając standardem zarządzania stanem w React Native i aplikacjach webowych.
Najważniejsze
Redux — wzorzec architektoniczny i biblioteka do zarządzania stanem, oparty na trzech zasadach: jedyne źródło prawdy (single source of truth), stan tylko do odczytu (read-only) i zmiany przez czyste funkcje. W przeciwieństwie do MVC, gdzie model może zmieniać stan w nieprzewidywalny sposób, Redux gwarantuje determinizm: przy tych samych danych wejściowych wynik jest zawsze taki sam.
Redux został zainspirowany architekturą Flux od Facebooka i językiem Elm. Główna różnica w stosunku do Flux — pojedynczy Store zamiast wielu. W Redux cały stan aplikacji — obiekty, tablice, flagi ładowania — przechowywany jest w jednym drzewie. Upraszcza to debugowanie, testowanie i przywracanie stanu (time-travel debugging). Deweloper może zapisać cały Store, odtworzyć sekwencję Action i zobaczyć, jak zmieniał się stan na każdym kroku.
Według danych State of JS 2025, 68% respondentów korzystających z zarządzania stanem wybiera Redux lub Redux Toolkit. Narzędzie jest wspierane przez wszystkie nowoczesne frameworki: React, React Native, Angular, Vue, a nawet czysty JavaScript bez frameworków.
Unidirectional data flow — kluczowa zasada Redux, w której dane poruszają się ściśle w jednym kierunku: View → Action → Dispatch → Reducer → Store → View. Żaden komponent nie może bezpośrednio zmienić Store. View tylko subskrybuje zmiany przez useSelector lub connect i inicjuje zmiany przez dispatch.
Cykl działania Redux: użytkownik naciska przycisk → komponent wywołuje dispatch({ type: 'INCREMENT' }) → Store przekazuje Action do Root Reducer → Reducer oblicza nowy stan → Store powiadamia subskrybentów → View przerysowuje się z nowymi danymi. Ten cykl gwarantuje, że każda zmiana ma wyraźną przyczynę w postaci konkretnego Action.
DevTools — wbudowane narzędzie Redux do monitorowania każdego Action, stanu Store i czasu wykonania. Deweloper widzi listę wszystkich wysłanych Action, różnicę stanu (diff) przed i po, oraz może cofnąć się do dowolnego poprzedniego stanu. To sprawia, że debugowanie złożonych stanów jest dziesiątki razy szybsze w porównaniu do zwykłego logowania.
Store — obiekt zawierający pełne drzewo stanu. Tworzony przez configureStore (RTK) lub createStore. Store udostępnia trzy metody: getState() do odczytu, dispatch(action) do zmiany i subscribe(listener) do subskrypcji. W Redux Toolkit Store zawiera już middleware, DevTools i obsługę slice'ów.
import { configureStore } from '@reduxjs/toolkit'
interface CounterState {
value: number
}
const initialState: CounterState = { value: 0 }
function counterReducer(
state = initialState,
action: { type: string }
): CounterState {
switch (action.type) {
case 'INCREMENT':
return { value: state.value + 1 }
default:
return state
}
}
const store = configureStore({ reducer: counterReducer })
store.dispatch({ type: 'INCREMENT' })
console.log(store.getState()) // { value: 1 }Action i Action Creator — Action to obiekt z obowiązkowym polem type (stała string) i opcjonalnym payload (dane). Action Creator — funkcja zwracająca Action. W Redux Toolkit używa się createAction do generowania Action z automatyczną typizacją.
Reducer — czysta funkcja, otrzymująca bieżący stan i Action, zwracająca nowy stan. Reducer nie powinien: mutować state (zwraca nowy obiekt), wywoływać API, generować losowych liczb ani odwoływać się do Date. Niezmienność zapewniana jest przez operator spread ... lub Immer (wbudowany w RTK).
| Komponent | Obowiązek | Ograniczenia |
|---|---|---|
| Store | Przechowywanie stanu, dispatch, subscribe | Jeden na aplikację |
| Action | Opis zamiaru zmiany stanu | Musi mieć type |
| Reducer | Obliczanie nowego stanu | Czysta funkcja, bez efektów ubocznych |
| Dispatch | Wysyłanie Action do Reducer | Synchroniczny domyślnie |
| Selector | Wydobywanie danych z Store | Memoizacja przez createSelector |
Middleware — łańcuch funkcji wstawiany między wywołanie dispatch a moment, gdy Action dociera do Reducer. Każdy middleware otrzymuje API Store i może logować, modyfikować, opóźniać lub anulować Action. Redux Thunk — standardowy middleware dla operacji asynchronicznych, pozwalający dispatch-ować funkcje zamiast obiektów.
import { createAsyncThunk } from '@reduxjs/toolkit'
export const fetchUser = createAsyncThunk(
'users/fetchById',
async (userId: number, { rejectWithValue }) => {
const response = await fetch(`/api/users/${userId}`)
if (!response.ok)
return rejectWithValue('Failed to fetch')
return await response.json()
}
)Popularne middleware: Redux Thunk — dla prostych wywołań asynchronicznych, Redux Saga — dla złożonych scenariuszy z sagami-generatorami (debounce, race, równoległe zapytania), Redux Observable — oparty na RxJS dla reaktywnych strumieni. W Redux Toolkit middleware podłącza się przez parametr middleware w configureStore.
Według danych ankiety State of JS 2025, Thunk jest używany w 72% projektów Redux, Saga — w 18%, Observable — w 5%. Dla większości aplikacji kombinacja Thunk + RTK Query wystarcza, aby pokryć 95% scenariuszy asynchronicznej pracy z danymi.
Redux Toolkit (RTK) — oficjalny, zalecany sposób pisania logiki Redux, wydany w 2019 roku. RTK zawiera configureStore, createSlice, createAsyncThunk i createEntityAdapter, redukując boilerplate Redux o 60-70%. Zamiast ręcznego tworzenia Action Creator, Reducer i typów używa się jednego createSlice.
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment(state) { state.value += 1 },
incrementByAmount(state, action: PayloadAction<number>) {
state.value += action.payload
}
}
})
export const { increment, incrementByAmount } = counterSlice.actions
export default counterSlice.reducerRTK Query — wbudowane rozwiązanie do pracy z API oparte na Redux Toolkit. Pozwala definiować endpointy deklaratywnie przez createApi z automatycznym generowaniem hooków, cache'owaniem, unieważnianiem tagów i optymistycznymi aktualizacjami. RTK Query zastępuje ręczne pisanie Thunk, Reducer i Selector dla każdego zapytania API.
Entity Adapter — narzędzie createEntityAdapter do normalizacji kolekcji encji. Dostarcza wbudowane reducery CRUD, selektory i sortowanie dla tablic obiektów. Jeśli w Store przechowywane są listy użytkowników, produktów lub zamówień — Entity Adapter redukuje kod redukcji o 80%.
React Native Redux — standardowe połączenie dla aplikacji mobilnych w JavaScript. Redux integruje się przez Provider z react-redux, otaczający główny komponent aplikacji. Hooki useSelector i useDispatch dają komponentom dostęp do stanu bez props drilling. Persist — redux-persist zapisuje Store w AsyncStorage lub MMKV, przywracając stan po restarcie aplikacji.
Middleware dla React Native: redux-flipper do debugowania przez Flipper, redux-observable dla reaktywnych strumieni z natywnymi sterownikami, react-native-mmkv dla szybkiego trwałego przechowywania. Wtyczka nawigacyjna redux-first-router łączy ekrany ze Store, umożliwiając przywracanie stanu ekranu po powrocie.
W React Native Redux jest używany razem ze strategią network-first: aplikacja najpierw próbuje załadować dane z serwera, następnie cache'uje w Store przez RTK Query lub redux-persist. Tryb offline osiągany jest przez kombinację Redux + NetInfo + kolejki Action do ponownego wysłania po przywróceniu połączenia.
Często zadawane pytania
Redux — pełnoprawne rozwiązanie z Store, DevTools, Middleware i niezmiennym stanem. Context API — wbudowany mechanizm React do przesyłania danych bez props drilling. Context nadaje się do globalnych motywów i lokalizacji, Redux — do złożonego stanu z operacjami asynchronicznymi, cache'owaniem i debugowaniem. W dużych aplikacjach Context powoduje niepotrzebne przerenderowania, Redux z selektorami rozwiązuje ten problem.
Immer — biblioteka do niezmiennej pracy ze stanem, wbudowana w Redux Toolkit. Immer pozwala pisać reducery tak, jakbyś bezpośrednio mutował state: state.value += 1. Pod maską Immer tworzy obiekt proxy (draft), śledzi zmiany i zwraca nowy niezmienny obiekt. Zmniejsza to objętość kodu reducertów o 50% i eliminuje przypadkowe mutacje.
Logika Redux jest testowana izolowanie: Reducer — czysta funkcja, wystarczy wywołać z różnymi Action i sprawdzić wynik. Action Creator — sprawdzić zwracany obiekt. Thunk — zamokować API, wywołać dispatch i sprawdzić, które Action zostały wysłane. Komponent z useSelector — użyć Provider z testowym Store w rendererze. Redux DevTools pomagają napisać test, odtwarzając sekwencję Action z rzeczywistej sesji.
useState wystarcza do lokalnego stanu jednego komponentu: tekst pola, otwarty/zamknięty modal. Redux jest potrzebny, gdy stan jest współdzielony między wieloma ekranami, wymaga asynchronicznej synchronizacji (dane z serwera), powinien być zachowany między restartami aplikacji (persist) lub wymaga debugowania time-travel. Dla małych aplikacji Redux jest zbędny — użyj Context + useReducer.
Normalizr — biblioteka do normalizacji zagnieżdżonych danych w płaską strukturę Store. Zamiast przechowywania głębokich obiektów typu user.posts[0].comments, normalizacja tworzy słowniki: entities.users, entities.posts, entities.comments z odnośnikami po ID. Upraszcza to aktualizację jednej encji we wszystkich miejscach i przyspiesza selektory. Redux Toolkit zaleca znormalizowane dane dla złożonych modeli.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również