Why has it been created
This complexity is difficult to handle as we‘re mixing two concepts that are very hard for the human mind to reason about:mutation and asynchronicity.I call them Mentos and Coke. Both can be great in separation, but together they create a mess. Libraries like React attempt to solve this problem in the view layer by removing both asynchrony and direct DOM manipulation. However, managing the state of your data is left up to you. This is where Redux enters.
What does it do
Following in the steps of Flux,CQRS, and Event Sourcing, Redux attempts to make state mutations predictable by imposing certain restrictions on how and when updates can happen. These restrictions are reflected in thethree principlesof Redux.
Core concepts
1. Your app’s state is described as a plain object.This object is like a “model” except that there are no setters. This is so that different parts of the code can’t change the state arbitrarily, causing hard-to-reproduce bugs.
{ todos: [{ text: ‘Eat food‘, completed: true }, { text: ‘Exercise‘, completed: false }], visibilityFilter: ‘SHOW_COMPLETED‘ }
2. To change something in the state, you need to dispatch an action. An action is a plain JavaScript object that describes what happened. Enforcing that every change is described as an action lets us have a clear understanding of what’s going on in the app. If something changed, we know why it changed. Actions are like breadcrumbs of what has happened.
{ type: ‘ADD_TODO‘, text: ‘Go to swimming pool‘ } { type: ‘TOGGLE_TODO‘, index: 1 } { type: ‘SET_VISIBILITY_FILTER‘, filter: ‘SHOW_ALL‘ }
3.Finally, to tie state and actions together, we write a function called a reducer. Again, nothing magic about it—it’s just a function that takes state and action as arguments, and returns the next state of the app. It would be hard to write such a function for a big app, so we write smaller functions managing parts of the state:
function visibilityFilter(state = ‘SHOW_ALL‘, action) { if (action.type === ‘SET_VISIBILITY_FILTER‘) { return action.filter; } else { return state; } } function todos(state = [], action) { switch (action.type) { case ‘ADD_TODO‘: return state.concat([{ text: action.text, completed: false }]); case ‘TOGGLE_TODO‘: return state.map((todo, index) => action.index === index ? { text: todo.text, completed: !todo.completed } : todo ) default: return state; } }
Three principle single
single source of truth
The state of your whole application is stored in an object tree within a single store.
Some functionality which has been traditionally difficult to implement - Undo/Redo, for example - can suddenly become trivial to implement, if all of your state is stored in a single tree.
State is read-only
The only way to change the state is to emit an action, an object describing what happened.
This ensures that neither the views nor the network callbacks will ever write directly to the state. Instead, they express an intent to transform the state. Because all changes are centralized and happen one by one in a strict order, there are no subtle race conditions to watch out for. As actions are just plain objects, they can be logged, serialized, stored, and later replayed for debugging or testing purposes.
Changes are made with pure functions
To specify how the state tree is transformed by actions, you write pure reducers.