Redux ułatwia nam pracę ze stanem, a jego implementacja w ReactJS stała się najbardziej popularnym sposobem tworzenia warstw danych opisanych przez Facebook-a jako Flux. Nie będę jednak opisywał podstaw pracy ze stanem w ReactJS ani samego sensu jego stosowania . W tym artykule chcę się skupić na wytłumaczeniu jakie elementy musi zawierać aplikacja używająca Reduxa oraz w jaki sposób napisać ich najprostsze implementacje.
Poniższy wykres zawiera kompletny opis implementacji Redux w aplikacji z React:
Redux

Znaczenie pojęć w Redux

Duża liczba nowych pojęć w Redux każdego na początku przytłoczy, ale warto zauważyć, że cały czas obracamy się w rejonie znanych JavaScriptowych obiektów (Action, Store) i funkcji (Reducer, Dispatch).

  • Store – obiekt JSON, który przechowuje stan całej aplikacji
  • Reducer – odbiera akcję i zmienia aktualny stan (często funkcją „switch case”)
  • Action – zdefiniowany obiekt z danymi zawierający część „type” i zazwyczaj „payload”
  • Dispatch – wywołuje akcję, może zawierać payload

Implementacja Redux w React

Store

Rozpoczynamy od stworzenia Store czyli stanu całej aplikacji (w głównym pliku index.js):

const store = createStore(todoApp)

przy bardziej złożonych aplikacjach reducerów będzie więcej i nie unikniemy middleware’a np. do obsługi HTTP:

const store = createStore(combineReducers({reducer1, reducer2}, applyMiddleware(thunk))

Następnie całą aplikację zamykamy w znacznik Provider dodając store={store}

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

Reducer

Przykładowy Reducer, który dodaje lub odejmuje podaną liczbę może mieć postać:

function calcApp(state = initialState, payload) {
  switch (action.type) {
    case ADD_NUMBER:
      return {…state, calc: state.calc + payload};
    case SUBTRACT_NUMBER:
      return {…state, calc: state.calc - payload};
    default:
      return state
  }
}

Action

Obiekt typu Action musi zawierać typ, zazwyczaj zawiera również payload jednak przy niektórych akcjach (np. usuń) nie jest to konieczne:

{
   type: ADD_NUMBER,
   payload: 5
}

Dispatch

W każdym Smart Componencie pojawią się Dispatch-ery, który umożliwią nam zmianę stanu aplikacji. Należy je zaimplementować używając mapDispatchToProps:

const mapDispatchToProps = (dispatch) => {
  return {
     onIncrement: () => dispatch(action_name),
     onDecrement: (value) => dispatch({type: ‘SUBTRACT_NUMBER’, payload: value})
}

Dostęp do propsów ułatwi nam użycie mapStateToProps:

const mapStateToProps = (state) => {
  return state;
}

Ostatecznie wspomniane funkcje wystarczy połączyć z komponentem używając connect:

const Name = connect(mapStateToProps, mapDispatchToProps)(Name)

Mam nadzieję, że ten opis będzie pierwszym krokiem do zrozumienia jak zaimplementować Redux. Jako następny krok polecam przejrzenie aplikacji TODO App pokazanej na stronie redux.com lub bezpośrednio na ich github-ie.