ReduxReducers / Redux


The function you pass to createStore() is called a reducer. It's a simple function that takes in a state, and returns another state.

reducer(state, action) state

Most reducers use switch inside them to do different things depending on the action.

function reducer (state, action) {
  switch (action.type) {
    case 'PUBLISH':
      return { ...state, published: true }
    case 'UNPUBLISH':
      return { ...state, published: false }
    case 'UPDATE':
      return { ...state, }
      return state

Why do we keep using ...? Next


Never modify the state! That's the Redux way of doing things. This is called immutability, in other words, never having to mutate.

function reducer (state, action) {   switch (action.type) {     case 'PUBLISH': 
      state.published = true  Avoid      return state 

      return { ...state, published: true }  

This seems like a hassle at first, but it makes your app faster in the long run. You'll be able to check if a state has changed.

var orig = { message: 'Hello' }
var copy = orig
orig.message = 'Hola'
orig === copy  true
State mutations break equality checks.

If your React app seems like it's not updating, it's probably because you're mutating state. It'd make state === oldState even if they changed, making React skip doing updates.

What happens when my reducer gets very big? Next

Combining reducers

Let's say you app has articles and users. If we put everything into one reducer, we'll be writing a very long function! There's a better way. Imagine your store state looks like this:

  articles: {},
  users: {}

You can use combineReducers to make two reducers, each working on one part. This is only useful if each reducer works on a single part of your state.

import { combineReducers, createStore } from 'redux' 

function articles (state, action) {
  ...state is state.articles here.
function users (state, action) {
  ...state is state.users here.
let reducer = combineReducers({ articles, users })let store = createStore(reducer) 

Also see: combineReducers()

What do you mean "on a single part"? Next

State subtrees

Think of your state as a tree. It has branches which have their own branches and leaves, and so on. A subtree is one branch of that tree.

state = { 
  profile: {
    name: 'John Jones',
    private: true
  },  photos: [        ] } 
state.profile is a subtree of the state tree.

combineReducers() lets you break apart your reducer. Your reducers will only operate in their own subtree, like state.profile above.

function profile (state, action) {
  if (action.type === 'PUBLISH') {
    state is limited to state.profile here.
    return { ...state, private: false }
let reducer = combineReducers({ profile,  })

This reducer can't see! This is usually a good thing. As your store reducers get bigger, you're assured that they only play in one part of your state tree.

What if my I need my reducers to do more than that? Next

Reduce reducers

Another approach to combining reducers is to use reduce-reducers. Unlike combineReducers(), these sub-reducers will be able to work on the entire tree.

import reduceReducers from 'reduce-reducers' 

function profiles (state, action) {
  See the whole state here.
function photos (state, action) {
  Here, as well.
let reducer = reduceReducers(profiles, photos)
let store = createStore(reducer)

reduce-reducers is a 3rd-party package. It's one of the many plugins available in the Redux ecosystem in npm.

Also see: reduce-reducers

Let's recap what we've learned. Next


Reducers are functions that take a state, and return a new state.

reducer(state, action) state

Immutable: reducers work your state in a way that never mutates objects.

state.published = true  
return { ...state, published: true }  

Composing: You can use combineReducers() or reduce-reducers to break a big reducer into smaller reducers.

function profile (state, action) {  }
function photos (state, action) {  }

combineReducers({ profile, photos })

Let's use Redux with React. Next