The Core Principles of Redux (Part 2): Changes Are Made with Pure Functions #106
📖 Introduction
Following our exploration of the first two core principles of Redux, this article dives into the third and final principle: changes are made with pure functions. We will learn about reducers and how they are used to update the state in a Redux application.
📚 Prerequisites
Before we begin, please ensure you have a solid grasp of the following concepts:
- The first two principles of Redux.
- The concept of pure functions.
🎯 Article Outline: What You'll Master
In this article, you will learn:
- ✅ The Third Principle of Redux: Understanding why changes must be made with pure functions.
- ✅ Reducers: What they are and how they work.
- ✅ Core Implementation: How to write a simple reducer for a to-do list application.
🧠 Section 1: The Core Concepts of Reducers
The third principle of Redux is that to specify how the state tree is transformed by actions, you write pure functions called reducers.
A reducer is a function that takes the previous state and an action as arguments, and returns the next state. It's called a reducer because it's the type of function you would pass to Array.prototype.reduce().
A reducer must be a pure function. This means that:
- It does not modify its arguments.
- It does not have any side effects (e.g., making API calls, calling non-pure functions).
- Given the same inputs, it will always return the same output.
By using pure functions, Redux ensures that the state is updated in a predictable and consistent way.
💻 Section 2: Deep Dive - Implementation and Walkthrough
Let's write a simple reducer for our to-do list application.
2.1 - The To-Do List Reducer
const initialState = {
todos: [],
visibilityFilter: 'SHOW_ALL'
};
function todoApp(state = initialState, action) {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
todos: [
...state.todos,
{
id: action.id,
text: action.text,
completed: false
}
]
};
case 'TOGGLE_TODO':
return {
...state,
todos: state.todos.map(todo =>
(todo.id === action.id)
? {...todo, completed: !todo.completed}
: todo
)
};
default:
return state;
}
}
Step-by-Step Code Breakdown:
function todoApp(state = initialState, action): We define our reducer function. It takes the currentstateand anactionas arguments. We also provide a default value for the state.switch (action.type): We use aswitchstatement to handle different action types.case 'ADD_TODO': If the action type isADD_TODO, we return a new state object with the new to-do item added to thetodosarray....state: We use the spread syntax to copy the existing state....state.todos: We use the spread syntax again to copy the existingtodosarray.
case 'TOGGLE_TODO': If the action type isTOGGLE_TODO, we return a new state object with thecompletedproperty of the corresponding to-do item toggled.default: If the action type doesn't match any of our cases, we return the current state.
💡 Conclusion & Key Takeaways
In this article, we've learned about the third core principle of Redux: that changes are made with pure functions called reducers. This is the final piece of the puzzle that makes Redux a powerful and predictable state management solution.
Let's summarize the key takeaways:
- Reducers are pure functions that take the previous state and an action, and return the next state.
- They are the only way to change the state in a Redux application.
- By using pure functions, Redux ensures that the state is updated in a predictable and consistent way.
Challenge Yourself:
To solidify your understanding, try to add a REMOVE_TODO action to the todoApp reducer that removes a to-do item from the todos array.
➡️ Next Steps
You now have a solid understanding of the three core principles of Redux. In the next article, "Redux Actions and Action Creators (Part 1)", we will take a deeper dive into actions and learn how to use action creators to make our code more maintainable.
Thank you for your dedication. Stay curious, and happy coding!
glossary
- Reducer: A pure function that takes the previous state and an action, and returns the next state.
- Pure Function: A function that, given the same inputs, will always return the same output and has no side effects.
- Side Effect: Any application state change that is observable outside the called function other than its return value.