Conclusion First
This is a repost of the article from zenn.
To understand Redux, if you can understand this diagram (source: Redux Application Data Flow), you’re 90% there.
- From user input, (ActionCreator) creates an Action
- Dispatch (send) the Action to Store (where state is managed)
- Pass the dispatched Action to Reducer (where state is changed)
- Store saves the new State created by Reducer
- Reference data from Store and render in View (screen)
If there are any corrections like “This is wrong!” or “This mechanism is also used!”, please give me feedback! (That’s partly why I’m writing this!)
What is Redux
Redux is a framework for managing the state of UI that React handles.

In React, Flux is proposed for the data flow to manage state, but Redux is designed to be more manageable by extending the Flux concept. While it can be used with AngularJS or jQuery, using it with React is better.
Redux’s Three Principles
Redux’s basic design is based on the following three principles. Let’s look at them in order.
Single source of truth
This principle can be summarized as follows.
- The entire application’s state is created as a single object in tree form and stored in a single store
- Since State is easy to store, it’s easy to create universal applications
- Since State is single, it’s easy to debug and develop
The following diagram shows the State structure of a sample application using Redux DevTools.

In other words, you cannot create multiple Stores like this:
const store = createStore(sample);
const store2 = createStore(sample);
State is read-only
This principle states:
- The only means to change state is to issue and execute an Action object with the change content
- Views or callbacks cannot directly change the state
- Changes are made one by one in order
- Since Actions are objects, they can be saved and are easy to test
Mutations are written as pure functions
And this is the final principle.
- How actions change state is done in “Reducers”
- “Reducers” are functions that receive state and action and return new state
- The key point is not to change the current State object, but to create and return a new State object
- When developing, start with one Reducer for the application, and as it grows, split the Reducers
Overall Structure
Now, let’s check the overall structure again (source: Redux. From twitter hype to production). This diagram is more abstracted than the one shown at the beginning. There are new elements, but I’ll explain them later, so don’t worry about them here.
- From user input, ActionCreator creates an Action
- Dispatch (send) the Action to Store
- Pass the dispatched Action to Reducer
- Store saves the new State created by Reducer
- Reference data from Store and render in View
Now, I’d like to explain with a specific application example, but before that, let me roughly explain the components.
Components
There are the following 7 components. Let’s look at them one by one.
- View
- ActionCreator
- Action
- Middleware
- State
- Reducer
- Store
View: The screen users see
View refers to the screen actually displayed to users. Since users click buttons or input text to generate events, this screen is the starting point of event processing.

ActionCreator: Generates actions
ActionCreator, as the name suggests, performs the process of generating actions. In the diagrammed part, it corresponds to Actions shown in blue dialogs.

Action: User’s input action
Action refers to the action that the user inputs. For example, clicking a button or inputting text. When clicking a button triggers multiple processes, multiple actions may be issued for a single user input.

Middleware: Watches actions and incorporates side effects
Middleware monitors the issuance of actions and performs processing to incorporate side effects for certain specific processes. For example, when clicking a button triggers an API call to the server, this Middleware handles the connection processing to the API. Conversely, for simple processes that just change the View’s state and don’t interact with the server - actions without side effects - Middleware processing is not involved.

Reducer: The only thing that can rewrite the application’s state
Reducer is the only thing that can rewrite the application’s state. As in Redux’s basic design Single source of truth, only this Reducer can rewrite State. It has the role of propagating processing from actions.

State: The application’s state
State indicates the application’s state. For example, states like whether a checkbox is checked, or whether data was successfully retrieved via API call.

Store: Saves the application’s state
Store is the place that saves the application’s state. It contains State, and when State is changed by Reducer, the State saved in Store is rewritten.

Processing Flow
Now, let’s look at the processing flow using a task management TODO app as an example.
Here’s the task management TODO app.
User input issues an Action
Let’s look at a use case where we add a task by inputting “Do muscle training” and clicking the “Add” button to add the task to the TODO list item.

First, define the action to add a task.
export const ADD_TODO = "ADD_TODO";
export const addTodo = content => ({
type: ADD_TODO,
payload: {
id: ++nextTodoId,
content
}
});
Then, to dispatch (send) the action defined here from the View, add processing to InputWithButton. (Having UI components hold state + domain knowledge is an anti-pattern in some cases, but here I’ll explain in this form to understand the processing flow.)

class InputWithButton extends React.Component {
constructor(props) {
super(props);
this.state = { input: "" };
}
updateInput = (input) => {
this.setState({ input });
};
handleAddTodo = () => {
this.props.addTodo(this.state.input);
this.setState({ input: "" });
};
render() {
return (
<div>
<input
onChange={(e) => this.updateInput(e.target.value)}
value={this.state.input}
/>
<button className="add-todo" onClick={this.handleAddTodo}>
Add
</button>
</div>
);
}
}
Here, the text input to the input is:
this.state = { input: "" };
Stored in local State like this, and the Action is dispatched when the add button is pressed.
<button className="add-todo" onClick={this.handleAddTodo}>
Add
</button>
Also, handleAddTodo processes emptying the input at the same time as dispatching the action.
handleAddTodo = () => {
this.props.addTodo(this.state.input);
this.setState({ input: "" });
};
ADD_TODO is a pre-defined action.
Here, ActionCreator generates the action.
Pass the propagated (dispatched) Action to Reducer, Reducer updates State and saves it to Store
Reducer receives the dispatched Action and executes processing to rewrite the Store saved in the Store according to that Action.
const initialState = {
allIds: [],
byIds: {}
};
export default function(state = initialState, action) {
switch (action.type) {
case ADD_TODO: {
const { id, content } = action.payload;
return {
...state,
allIds: [...state.allIds, id],
byIds: {
...state.byIds,
[id]: {
content,
completed: false
}
}
};
}
...
allIds represents all tasks, and when the action ADD_TODO is dispatched, the newly created TODO task is added to the state allIds.
Reference data from Store and render in View
When a new TODO task is added, that change is also reflected in the View.

Here, because the TodoList component is monitoring the State saved in the Store, it’s immediately reflected.

const TodoList = ({ todos }) => (
<ul className="todo-list">
{todos && todos.length
? todos.map((todo, index) => {
return <TodoItem key={`todo-${todo.id}`} todo={todo} />;
})
: "No tasks."}
</ul>
);
const mapStateToProps = (state) => {
const { visibilityFilter } = state;
const todos = getTodosByVisibilityFilter(state, visibilityFilter);
return { todos };
};
export default connect(mapStateToProps)(TodoList);
Let’s move to where getTodosByVisibilityFilter is defined.
Here selector appears for the first time,
but this is the person who processes/selects data when retrieving the store’s state before throwing it to the view.
In this case, it processes the data to be retrieved by filtering with “all, completed, incomplete”.
export const getTodosByVisibilityFilter = (store, visibilityFilter) => {
const allTodos = getTodos(store);
switch (visibilityFilter) {
case VISIBILITY_FILTERS.COMPLETED:
return allTodos.filter(todo => todo.completed);
case VISIBILITY_FILTERS.INCOMPLETE:
return allTodos.filter(todo => !todo.completed);
case VISIBILITY_FILTERS.ALL:
default:
return allTodos;
}
};
So the processing to bring data from the original store is done by this getTodos.
export const getTodos = store =>
getTodoList(store).map(id => getTodoById(store, id));
Now we’ve understood the series of flows performed when adding a todo task.
This time, since it was a simple application without server interaction, it was simple processing without Middleware, but when actually creating a service, a more complex design will be required. About this in the next article.
I hope this helps those learning Redux even a little! If you have any advice or questions, please feel free to send them via twitter DM or comments!