# Redux demystified - 2: combineReducers

This post is a continuation of [Redux demystified - 1](https://blog.whatthecode.academy/redux-demystified). We understood the implementation of **createStore** and how we can manage the state when there is a single reducer. But that was just a simple example. Usually, any web app will have many different logically separated state objects which would need their own reducers.

Eventually Redux will accept only a single state object and a single reducer function that manages the overall state. So in order to combine multiple state objects and reducers, the redux provides a function named.... **combineReducers**, wasn't too hard to guess I believe.

We will add a new functionality to our example in the previous article, where we can add members to any of the two teams - Avengers and Justice League.

```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <script
            src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js"
            integrity="sha512-1/8Tj23BRrWnKZXeBruk6wTnsMJbi/lJsk9bsRgVwb6j5q39n0A00gFjbCTaDo5l5XrPVv4DZXftrJExhRF/Ug=="
            crossorigin="anonymous"
            referrerpolicy="no-referrer"
        ></script>
        <title>Heroes</title>
    </head>
    <body>
        <main class="members">
            <label for="name">Member Name:</label>
            <input type="text" id="name" autocomplete="name" placeholder="enter member name"/>
            <label for="team">Choose Team</label>
            <select id="team" name="team">
                <option value="Avengers">Avengers</option>
                <option value="Justice League">Justice League</option>
            </select>
            <button id="add">Add</button>
            <ul class="team-list"></ul>
            <label>Filters: 
                <ul class="filters">
                    <li class="filter selected">All</li>
                    <li class="filter">Avengers</li>
                    <li class="filter">Justice League</li>
                </ul>
            </label>
            
        </main>
        <style>
            .member,
            .members,
            .team-list {
                display: flex;
                justify-content: center;
                align-items: center;
            }

            .members,
            .team-list {
                flex-direction: column;
            }

            .member {
                gap: 10px;
            }

            .filters {
                list-style: none;
                display: flex;
                justify-content: center;
                align-items: center;
                gap: 10px;
            }

            .filter {
                text-decoration: underline;
                color: blue;
                cursor: pointer;
            }

            .selected {
                text-decoration: none;
                color: black;
                cursor: default;
            }

        </style>
        <script>
            // member reducer function
            const membersReducer = (state = [], action) => {
                switch (action.type) {
                    case 'ADD_MEMBER':
                        return [
                            ...state,
                            action.payload.member
                        ]
                    case 'REMOVE_MEMBER':
                        return state.filter(
                            member =>
                                member.id !== parseInt(action.payload.id)
                        )
                    default:
                        return state
                }
            }

            // filter reducer function
            const filterReducer = (state = 'All', action) => {
                switch (action.type) {
                    case 'FILTER_MEMBERS':
                        return action.payload.filter
                    default:
                        return state
                }
            }

            const combinedReducer = Redux.combineReducers({
                members: membersReducer,
                filter: filterReducer,
            })

            const { getState, dispatch, subscribe } =
                Redux.createStore(combinedReducer)

            const membersList = document.querySelector('.team-list')
            const input = document.querySelector('#name')
            const addMember = document.querySelector('#add')
            const selectedTeam = document.querySelector('#team')
            const filters = document.querySelector('.filters')

            let count = 0

            // update filter on click
            const handleFilterMembers = e => {
                if (e.target.classList.contains('filter')) {
                    filters.querySelector('.selected').classList.remove('selected')
                    e.target.classList.add('selected')
                    dispatch({
                        type: 'FILTER_MEMBERS',
                        payload: {
                            filter: e.target.innerText,
                        },
                    })
                }
                renderMembers()
            }

            // enter key event handler
            const enterMemberHandler = e => {
                if (e.key === 'Enter') addMemberHandler()
            }

            // add button click event handler
            const addMemberHandler = () => {
                dispatch({
                    type: 'ADD_MEMBER',
                    payload: {
                        member: {
                            id: ++count,
                            name: input.value,
                            team: selectedTeam.value,
                        },
                    },
                })
                input.value = ''
            }

            // function to render the members list on state change
            const renderMembers = () => {
                const { members, filter } = getState()
                membersList.innerHTML = ''
                const listFragment = document.createDocumentFragment()
                const filteredMembers = filter !== 'All'
                    ? members.filter(member => member.team === filter)
                    : members
                filteredMembers.forEach(member => {
                    const memberItem = document.createElement('li')
                    memberItem.innerHTML = `<p style="font-size: 20px; padding: 0px 10px; border-radius: 5px; 
                    background: ${member.team === 'Avengers' ? 'red' : 'green'}">${member.name}</p><span class="delete" data-id=${member.id} onclick="onDelete(event)" style="cursor: pointer;">&#10060;</span>`
                    memberItem.classList.add('member')
                    listFragment.appendChild(memberItem)
                })
                membersList.appendChild(listFragment)
            }

            // delete click event handler
            const onDelete = e => {
                dispatch({
                    type: 'REMOVE_MEMBER',
                    payload: {
                        id: e.target.dataset.id,
                    },
                })
            }

            // subscribing renderAvengers to execute on state **change
            subscribe(renderMembers)

            addMember.addEventListener('click', addMemberHandler)
            input.addEventListener('keypress', enterMemberHandler)
            filters.addEventListener('click', handleFilterMembers)
        </script>
    </body>
</html>

``` 

The Heroes web app will now have two new features - to select a team and to filter the list based on the team,

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1657439909328/YAFh-7yzz.png align="left")

Earlier we had only one reducer that was used to handle adding and removing members. We have modified that reducer from **avengersReducers** to **membersReducer** to make it generic to add a member of different teams.

```js
const filterReducer = (state = 'All', action) => {
                switch (action.type) {
                    case 'FILTER_MEMBERS':
                        return action.payload.filter
                    default:
                        return state
                }
            }
```

And we have added a new reducer to handle the filter state which will have one of the values from - *'All'*, *'Avengers'*, and *'Justice League'*.

```js
const combinedReducer = Redux.combineReducers({
                members: membersReducer,
                filter: filterReducer,
            })

const { getState, dispatch, subscribe } = Redux.createStore(combinedReducer)
```

We use the **combineReducer** method from **Redux** to combine our two reducers, which will return the combined reducer. Then we call **createStore** method with **combinedReducer** as its argument. The combined state object will be an object with two properties, 
- **members**: an array of member objects
- **filter**: the selected filter among *'All'*, *'Avengers'*, and *'Justice League'*

```js
const handleFilterMembers = e => {
                if (e.target.classList.contains('filter')) {
                    filters.querySelector('.selected').classList.remove('selected')
                    e.target.classList.add('selected')
                    dispatch({
                        type: 'FILTER_MEMBERS',
                        payload: {
                            filter: e.target.innerText,
                        },
                    })
                }
                renderMembers()
            }
```

We have also added a click event handler on the list of filters which will update the filter state and then call **renderMembers** to update the UI.

```js
const renderMembers = () => {
                const { members, filter } = getState()
                membersList.innerHTML = ''
                const listFragment = document.createDocumentFragment()
                const filteredMembers = filter !== 'All'
                    ? members.filter(member => member.team === filter)
                    : members
                filteredMembers.forEach(member => {
                    const memberItem = document.createElement('li')
                    memberItem.innerHTML = `<p style="font-size: 20px; padding: 0px 10px; border-radius: 5px; 
                    background: ${member.team === 'Avengers' ? 'red' : 'green'}">${member.name}</p><span class="delete" data-id=${member.id} onclick="onDelete(event)" style="cursor: pointer;">&#10060;</span>`
                    memberItem.classList.add('member')
                    listFragment.appendChild(memberItem)
                })
                membersList.appendChild(listFragment)
            }
```

The **renderMembers** function first fetches the current members list and filter state from the **getState** method and then accordingly updates the UI and displays the list of heroes as per the selected filter.

Now that we understand when and how to use **combineReducers** method, let's understand how it works internally.

We know that the **combineReducers** expects an object as a parameter and returns a function that will serve as the combined reducer. Since the returned function will be a reducer we know it will have two parameters - a state and an action. Also, we can initialize that state with an empty object.

```js
const combineReducers = (reducers) => {
    return (state = {}, action) => {
        
    }
}
```
The ***reducers*** param is an object whose keys will be the individual state name and values will be the respective individual reducer. So we can use ```
Object.keys(reducers)
``` to iterate over the ***reducers*** object. Then use **reduce** higher-order method of the array to calculate the resultant state. You can learn and understand **reduce** in detail from [here](https://youtu.be/ti2PgUVR42w?t=3038)

```js
const combineReducers = (reducers) => {
    return (state = {}, action) => {
        return Object.keys(reducers).reduce((prevState, stateName) => {
            return {
                ...prevState,
                [stateName]: reducers[stateName](state[stateName], action)
            }
        }, state)
    }
}
```

We initialize the accumulator with the *state* param of returned combined reducer (empty object) and then the **reduce** method will iterate over each *stateName* and will update the resultant state object by executing each reducer and adding its respective returned state.

If the implementation is not completely understandable at the first glance then go through it a couple of times. Add debug points or console logs while using it to understand it better.

Now comment or remove the Redux CDN script tag, and add our implementation of **combineReducers** at the start of the JS code along with the implementation of **createStore** from the previous article. I have added it below for your convenience but definitely read the [previous article](https://blog.whatthecode.academy/redux-demystified) to understand the implementation of **createStore**

```js
const createStore = (reducer) => {
    let state
    let listeners = []

    const getState = () => state

    const dispatch = (action) => {
        state = reducer(state, action)
        listeners.forEach(listener => listener())
    }

    const subscribe = (listener) => {
        listeners.push(listener)
        return () => {
            listeners = listeners.filter(l => l !== listener)
        }   
    }

    return {
        getState,
        dispatch,
        subscribe
    }
}

const combineReducers = (reducers) => {
    return (state = {}, action) => {
        return Object.keys(reducers).reduce((prevState, stateName) => {
            return {
                ...prevState,
                [stateName]: reducers[stateName](state[stateName], action)
            }
        }, state)
    }
}

const Redux = {
    createStore,
    combineReducers
}

```

Now our app should continue to work as before without the need to import Redux library code. Test it out thoroughly.

I hope you were able to not only understand the use of **combineReducers** method but also its implementation. In the next article, I am going to demystify the implementation of the **Provider** component and the **connect** higher-order component of the **'react-redux'** library. Subscribe to my newsletter to be notified as soon as I publish it.
