Redux Overview

Redux Overview

Redux is a ‘state management system’ that maintains a master state object for your application. Various parts of your application (components, etc) can access and modify (via dispatching ‘actions’) the master state object or ‘store’. In modern UIs we have to track more and more state everyday.. (which tab is selected, do i show the spinner, is another thing highlighted, etc.). It’s good to have a single place to hold this state. Enter redux (‘reducers’ + ‘flux’).

tl;dr full example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

// $ npm init -y
// $ npm install --save redux

// ./app.js:
const {createStore, combineReducers} = require('redux');

const isSpinnerShown = (state = false, action) => {
if(action.type === 'SHOW_SPINNER') {
return action.value // arbitrary property made up to hold true/false
}

return state // if not the right type, do nothing to the state
}

const hitCounter = (state = 0, action) => {
if(action.type === 'ADD_HIT') {
return state + 1
}

return state // if not the right type, do nothing to the state
}

const store = createStore(combineReducers({isSpinnerShown, hitCounter}));

const unsubscribe = store.subscribe(function() {
console.log('subscribe', store.getState());
})

store.dispatch({ type: 'SHOW_SPINNER', value: true });
store.dispatch({ type: 'SHOW_SPINNER', value: false });

unsubscribe();

store.dispatch({ type: 'ADD_HIT' });
store.dispatch({ type: 'ADD_HIT' });

console.log(store.getState());


// node ./app.js

Walkthrough

We create a store using the ‘createStore’ method from redux. You should only create one store per application.

1
const {createStore} = require('redux');

The store takes a pure reducer function with a (state, action) => state signature.
NOTE: when creating the store, the reducer is called with something like:
(undefined, {type: '@@redux/INITf.l.k.h.l.v'}) to allow for initial values
to be set.
If you set an inital value as a parameter, it will be called with that initial value.

1
2
3
4
const store = createStore((state = 0, action)=>{ 
console.log('oldState', state, 'action', action);
return state+1; // DO NOT MUTATE THE PREVIOUS STATE ALWAYS RETURN A NEW STATE (new obj, array, etc)
}, <initialValueHere>);

We can use the store’s .subscribe()
method that executes each time an action is dispatched.
Subscribe also returns a function that can be called to unsubscribe.
This snippet also features the getState() method we use to access the state.

1
2
3
const unsubscribe = store.subscribe(function() {
console.log('subscribe', store.getState());
})

We trigger changes to the store’s state by ‘dispatching actions’. Actions are regular object literals
with only one rule: they must have a defined type property. You can add any other properties you wish and have them passed into the reducers.

1
2
3
4
5
6
7
store.dispatch({ type: 'MY_TYPE', otherField: 'otherValue' });
store.dispatch({ type: 'MY_TYPE' });

unsubscribe();

store.dispatch({ type: 'MY_TYPE' });
store.dispatch({ type: 'MY_TYPE' });

Managing multiple ‘sub-state’ values.

You can use reducer composition to create one root reducer with the store’s .combineReducers() method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const {createStore, combineReducers} = require('redux');

const isSpinnerShown = (state = false, action) => {
if(action.type === 'SHOW_SPINNER') {
return action.value // arbitrary property made up to hold true/false
}

return state // if not the right type, do nothing to the state
}

const hitCounter = (state = 0, action) => {
if(action.type === 'ADD_HIT') {
return state + 1
}

return state // if not the right type, do nothing to the state
}

const store = createStore(combineReducers({isSpinnerShown, hitCounter}));

.combineReducers() creates a reducer similar to:

1
2
3
4
5
6
7

const rootReducer = (state = {}, action) => {
return {
isSpinnerShown: isSpinnerShown(state.isSpinnerShown, action),
hitCounter: hitCounter(state.hitCounter, action),
}
}

Now… go and build something! :)

Share