From Redux Introduction, we know that there is only a single Store in a Redux application. When we want to split data-handling logic, we will combine Reducers instead of using many Stores. This tutorial shows you way to use Redux combineReducers()
function in a Redux example.
Full example with filtering and sorting: Redux Reducer example – filter & sort data
Contents
Overview
combineReducers
If we have state whose values seem to correspond to different reducing functions like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
const demoState = { books: [ { id: '123abcdefghiklmn', title: 'Origin', description: 'Origin thrusts Robert Langdon into ...', author: 'Dan Brown', published: 2017 }, { ... } ], filters: { text: 'ori', sortBy: 'published', startYear: undefined, endYear: undefined } }; |
We won’t use only one Reducer to handle Action logic but two Reducers: one for books
, and one for filters
. Now, combineReducers()
comes to be the solution.
It combines 2 reducing functions into a single reducing function that can be passed to createStore()
:
1 2 3 4 5 6 |
const rootReducer = combineReducers({ books: booksReducer, filters: filtersReducer }) const store = createStore(rootReducer); |
combineReducers rules
The Reducer that is passed to combineReducers()
function must satisfy these rules:
– For unrecognized Action: return the given state as the first argument.
(we usually return state
in default case of switch
statement)
– Never return undefined
.
– If the given state is undefined
: return the initial state. So the initial state must not be undefined
either.
Example Description
We will create a Redux Application that has:
– state that contains 2 components: books
array and filters
.
– 3 types of Actions:
+ 'ADD_BOOK'
, 'REMOVE_BOOK'
for books
.
+ 'FILTER_TEXT'
for filters
.
– 2 child Reducers (booksReducer
and filtersReducer
) that will be combined using combineReducers()
function.
We can add/remove books to/from books
, set filters.text
value.
Practice
Setup environment
In package.json:
1 2 3 4 5 6 7 8 9 |
{ ... "dependencies": { ... "babel-plugin-transform-object-rest-spread": "6.26.0", "redux": "3.7.2", "uuid": "3.2.1" } } |
Then run cmd yarn install
.
Add plugin to .babelrc
:
1 2 3 4 5 6 |
{ ... "plugins": [ "transform-object-rest-spread" ] } |
Create Redux Actions
Book Actions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
const addBook = ({ title = '', description = '', author = '', published = 0 } = {}) => ({ type: 'ADD_BOOK', book: { id: uuid(), title, description, author, published } }); const removeBook = ({ id } = {}) => ({ type: 'REMOVE_BOOK', id }); |
Filter Actions
1 2 3 4 |
const filterText = (text = '') => ({ type: 'FILTER_TEXT', text }); |
Create Redux Reducer
Books Reducer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const booksReducerDefaultState = []; const booksReducer = (state = booksReducerDefaultState, action) => { switch (action.type) { case 'ADD_BOOK': return [ ...state, action.book ]; case 'REMOVE_BOOK': return state.filter(({ id }) => id !== action.id); default: return state; } }; |
Filters Reducer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
const filtersReducerDefaultState = { text: '', sortBy: 'title', startYear: undefined, endYear: undefined }; const filtersReducer = (state = filtersReducerDefaultState, action) => { switch (action.type) { case 'FILTER_TEXT': return { ...state, text: action.text }; default: return state; } } |
Create Redux Store
1 2 3 4 5 6 |
const store = createStore( combineReducers({ books: booksReducer, filters: filtersReducer }) ); |
Subscribe & Unsubscribe
1 2 3 4 5 6 7 8 |
const unsubscribe = store.subscribe(() => { console.log(store.getState()); }); // store.dispatch(action)... unsubscribe(); // store.dispatch(action) << not do anything... |
Run and Check result
Full code:
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
import { createStore, combineReducers } from "redux"; import uuid from 'uuid'; const demoState = { books: [ { id: '123abcdefghiklmn', title: 'Origin', description: 'Origin thrusts Robert Langdon into the dangerous intersection of humankind’s two most enduring questions.', author: 'Dan Brown', published: 2017 } ], filters: { text: 'ori', sortBy: 'published', // published or title startYear: undefined, endYear: undefined } }; // action creators for Books Reducer const addBook = ({ title = '', description = '', author = '', published = 0 } = {}) => ({ type: 'ADD_BOOK', book: { id: uuid(), title, description, author, published } }); const removeBook = ({ id } = {}) => ({ type: 'REMOVE_BOOK', id }); const booksReducerDefaultState = []; // Books Reducer const booksReducer = (state = booksReducerDefaultState, action) => { switch (action.type) { case 'ADD_BOOK': return [ ...state, action.book ]; case 'REMOVE_BOOK': return state.filter(({ id }) => id !== action.id); default: return state; } }; // action creators for Filters Reducer const filterText = (text = '') => ({ type: 'FILTER_TEXT', text }); const filtersReducerDefaultState = { text: '', sortBy: 'title', startYear: undefined, endYear: undefined }; // Filters Reducer const filtersReducer = (state = filtersReducerDefaultState, action) => { switch (action.type) { case 'FILTER_TEXT': return { ...state, text: action.text }; default: return state; } } // Store const store = createStore( combineReducers({ books: booksReducer, filters: filtersReducer }) ); const unsubscribe = store.subscribe(() => { console.log(store.getState()); }); const book1 = store.dispatch(addBook({ title: 'Origin', description: 'Origin thrusts Robert Langdon into the dangerous intersection of humankind’s two most enduring questions.', author: 'Dan Brown', published: 2017 })); const book2 = store.dispatch(addBook({ title: 'Harry Potter and the Deathly Hallows', description: 'The seventh and final novel of the Harry Potter series.', author: 'J. K. Rowling', published: 2007 })); const book3 = store.dispatch(addBook({ title: 'The 100-Year-Old Man Who Climbed Out the Window and Disappeared', author: 'Jonas Jonasson', published: 2009 })); store.dispatch(removeBook({ id: book2.book.id })); store.dispatch(filterText('origin')); |
Result in Browser Console:
Source code
For running:
– yarn install
– yarn run dev-server
or yarn run build
, then yarn run serve
.