What Is A Redux Action? (React Architecture)
A Redux action is a plain JavaScript object that describes an event in an application, such as a todo being added. Its required type field names the event; optional data, often called a payload, gives it details. In React–Redux, code dispatches actions, reducers use them to calculate new state, and components read that state.
A Redux action is not an action hero. It cannot change state by itself, and it does not save your code from debugging.
That distinction is useful when you are learning React architecture. An action is a message. It reports what happened or what update is requested. Redux code uses that message to work out a new state in a clear, testable way. Here is how the pieces fit together, how to write and dispatch actions, and when Redux may be useful.
Redux Actions in React: Purpose and Data Flow
A Redux action is a plain JavaScript object that describes an event in an app. Redux requires the object to have a type property. In a React app, code dispatches the action to the Redux store, a reducer processes it, and React-Redux can help components read the resulting state.
Redux is a state management library, not a React feature. You can use Redux with other JavaScript setups, and you can build a React app without Redux. React-Redux connects React components to a Redux store.
The basic flow is:
- A user does something, such as clicking “Add todo.”
- Code dispatches an action describing that event.
- A reducer receives the current state and action.
- The reducer returns the next state.
- A subscribed component can read the updated state and render again.
An action does not edit the store directly. It gives the reducer information to use. This separation makes it easier to inspect which events occurred and how the app responded.
What does a Redux action look like?
An action is a JavaScript object with a type field. The type is a string that identifies the event, such as "todos/todoAdded". An action may also carry data, commonly in a payload field, but Redux does not require one fixed payload format.
For example:
{
type: "todos/todoAdded",
payload: {
id: 1,
text: "Read the Redux guide"
}
}
The type says what happened. The payload gives the reducer the details it needs. The exact fields depend on the event and your app.
A useful naming habit is to describe an event that happened, rather than phrase the type as an instruction to change data. "todos/todoAdded" describes a completed event. The reducer decides what that event means for state.
How actions fit into React–Redux
React-Redux provides hooks that let function components work with a Redux store. useDispatch() gives a component a way to dispatch actions. useSelector() lets it read selected state from the store.
A basic component might look like this:
import { useDispatch, useSelector } from "react-redux";
function TodoList() {
const dispatch = useDispatch();
const todos = useSelector((state) => state.todos);
function addTodo() {
dispatch({
type: "todos/todoAdded",
payload: { id: 1, text: "Read the Redux guide" }
});
}
return (
<section>
<button onClick={addTodo}>Add todo</button>
<ul>
{todos.map((todo) => (
<li key={todo.id} key={todo.id}>{todo.text}</li>
))}
</ul>
</section>
);
}
In a real app, each todo needs a unique key, and its ID should not be hard-coded. The example focuses on the dispatch flow: the component sends an action, but the reducer still determines the state update.
The main takeaway: components report events; reducers calculate state.
Action Types, Payloads, and Reducer Requirements
Action types name events, and payloads carry any related data. A reducer uses both to decide what state should come next. Reducers must not change existing state in place or perform side effects such as network requests; they should return state based on the current state and action.
What is an action type?
An action type is the string stored in an action’s type property. It helps reducers identify which event they are handling. Redux requires a type, but it does not prescribe one naming style.
For example, an app might use:
{ type: "cart/itemAdded", payload: { productId: "p7" } }
This type groups the event under cart and names the event itemAdded. Consistent naming helps people scan logs and code. It does not change how Redux works.
What is a payload?
A payload is additional information attached to an action. It is often stored in a payload field, but that convention is not mandatory in Redux core. The action should carry the information the reducer needs to handle the event.
A todo-add action might include text and an ID. A filter-change action might include a filter value. Avoid placing unrelated information in one action. A clear event and focused data are easier to test and understand.
What must a reducer do?
A reducer is a function that receives the current state and an action, then returns the next state. It should be pure: given the same state and action, it should return the same result without changing outside data or causing side effects.
A small reducer might look like this:
function todosReducer(state = [], action) {
switch (action.type) {
case "todos/todoAdded":
return [...state, action.payload];
default:
return state;
}
}
The spread syntax creates a new array with the old items and the new todo. The reducer does not push into the existing array. In Redux, changing existing state in place can break reliable updates and debugging tools.
A reducer should not fetch data, set timers, or make other external changes. Put asynchronous work in suitable middleware or Redux Toolkit facilities, then dispatch actions as work starts or finishes.
Action, action creator, and reducer compared
An action is the event object. An action creator is a function that makes that object. A reducer handles it. These are related parts, but they are not interchangeable.
| Term | What it is | Example |
|---|---|---|
| Action | Plain object describing an event | { type: "todos/todoAdded", payload: todo } |
| Action creator | Function that returns an action | todoAdded(todo) |
| Reducer | Function that calculates next state | Handles "todos/todoAdded" |
| Dispatch | Store method used to send an action | dispatch(todoAdded(todo)) |
For simple learning examples, writing an action object directly can make the flow visible. In a larger app, action creators reduce repeated typing and help keep action shapes consistent.
Dispatching Actions and Building Effective Redux Habits
Dispatching means sending an action to the Redux store. A component often dispatches after a user event, while a reducer handles the action and returns the next state. For typical Redux apps, Redux Toolkit’s createSlice can generate action creators and action types from reducer definitions.
Use Redux Toolkit for typical Redux apps
Redux Toolkit is the recommended standard way to write Redux logic in most Redux apps. Its createSlice function creates action creators and action types based on the reducer names in a slice.
import { createSlice } from "@reduxjs/toolkit";
const todosSlice = createSlice({
name: "todos",
initialState: [],
reducers: {
todoAdded(state, action) {
state.push(action.payload);
}
}
});
export const { todoAdded } = todosSlice.actions;
export default todosSlice.reducer;
This code may look like it changes state with push. Redux Toolkit uses Immer to let you write these update patterns while producing an immutable state update. Do not copy this style into a plain Redux reducer unless you are using a tool that provides this behavior.
A component can dispatch the generated action creator:
dispatch(todoAdded({ id: 2, text: "Review notes" }));
The action creator builds the object; dispatch sends it; the slice reducer handles it.
A practical implementation sequence
For a small feature, I use this sequence to keep the event, data, and state update clear:
- Prepare: Know the current state shape and the component that needs to read or update it.
- Name the event: Pick a meaningful event such as
todoAddedorfilterChanged. - Choose the data: Decide what details the reducer needs in the payload.
- Handle the event: Add reducer logic that returns the correct next state.
- Dispatch and verify: Trigger the action, then check both store state and the rendered UI.
For example, a filter control might dispatch { type: "todos/filterChanged", payload: "active" }. Its reducer updates the selected filter. A component using useSelector() can then read that filter and show the matching todos.
Worked scenarios: choosing an action
These are illustrative coding scenarios, not reports of specific production projects. They show how event design changes with the feature.
| Scenario | Action type | Possible payload | State result |
|---|---|---|---|
| Add a todo | todos/todoAdded |
Todo object | Add one todo |
| Change a filter | todos/filterChanged |
"active" |
Store selected filter |
| Mark a todo done | todos/todoToggled |
Todo ID | Change that todo’s status |
A useful check is to ask: “Could another developer tell what happened from this action?” If the answer is no, make the type more specific. Then ask whether the payload contains only the data needed for that event.
Keep actions suitable for debugging
Standard Redux tools work best when actions and state are serializable. In plain language, their values should be easy to record and inspect, such as strings, numbers, arrays, and plain objects. Functions, promises, and some special objects can make logs or replay tools harder to use.
This does not mean every app must use identical action shapes. It means predictable, inspectable data helps with debugging. Follow the rules of the middleware and tooling in your project.
Redux Skills, Project Applications, and Career Pathways
Understanding Redux actions means understanding a common state update pattern, not memorizing a list of commands. The skill is being able to describe an event, send the data it needs, and handle it with a predictable reducer. The same reasoning applies across projects, whether you use Redux Toolkit or another state approach.
When should you use Redux?
Redux can help when many parts of an app need shared state, or when a predictable update history and Redux tooling are useful. It is not required for every React component. State used by one component, such as whether its menu is open, may be simpler to keep in local React state.
| State example | Often a reasonable starting point |
|---|---|
| One component’s open or closed menu | Local React state |
| Shared account details read across screens | Consider centralized state |
| Complex updates that need clear event history | Consider Redux |
| A value used only while editing one small form | Local state may be enough |
These are starting points, not strict rules. Consider how many components need the value, how often it changes, and whether centralized updates solve a real problem.
How to test an action flow
Test the feature as a chain. First, confirm the action has the expected type and payload. Next, pass it with a known state to the reducer and check the returned state. Finally, verify that the component shows the expected result after dispatch.
For a todo feature, useful checks include:
- Does
todoAddedinclude the todo data the reducer needs? - Does the reducer return a state that includes the new todo?
- Does the component display it after dispatch?
- Does any action or reducer code mutate existing state or perform a side effect?
This approach helps locate a problem. If the reducer test passes but the screen does not update, inspect how the component selects state and how the store is connected.
Common mistakes to avoid
A frequent beginner mistake is to think that dispatching an action changes state by itself. Dispatch only sends the action into the Redux flow; reducer logic must handle it.
Other common mistakes include:
- Leaving out the required
typefield. - Giving the reducer too little data to process the event.
- Mutating state in a plain Redux reducer.
- Putting network requests or other side effects inside a reducer.
- Moving every small UI value into Redux without a clear need.
When debugging, inspect the exact action and the reducer branch that should handle it. That often reveals whether the issue is the event name, payload shape, or update logic.
Key takeaway
A Redux action is a message describing an event. It carries a required type and may carry a payload. Code dispatches it, a reducer calculates the next state, and React-Redux lets components read that state. Start with clear event names, keep reducers pure, and use Redux where shared state or its tools provide value.
Redux Action FAQ
These short answers cover the terms and decisions people most often ask about when learning Redux actions in a React app. Redux’s core rules are small: actions are objects with a type, reducers calculate state, and React-Redux provides common ways for components to dispatch and read updates.
Is a Redux action a function?
No. An action is a plain object. An action creator is a function that returns an action object.
What property must every Redux action have?
It must have a type property. Redux does not require a payload property.
Does a Redux action change state by itself?
No. Dispatch sends the action to the store. A reducer must handle it and return the next state.
Is Redux only for React?
No. Redux is a JavaScript state management library. React-Redux is the library commonly used to connect Redux with React components.
What is a Redux action payload?
A payload is optional data attached to an action, often in a payload field. It gives the reducer details needed to handle the event.
What does dispatch() do?
dispatch() sends an action to the Redux store so the relevant reducer logic can process it.
What does useDispatch() do?
The React-Redux useDispatch() hook gives a function component access to the store’s dispatch function.
What does useSelector() do?
The React-Redux useSelector() hook lets a component read selected data from the Redux store.
Should I write action types by hand?
You can, especially to learn the model. For typical Redux apps, Redux Toolkit’s createSlice generates action types and action creators.
Can a reducer make an API request?
No. Reducers should stay pure and should not perform side effects. Use suitable middleware or Redux Toolkit facilities for asynchronous work.
Should every React state value go in Redux?
No. Local state is often enough for a value used by one component. Consider Redux when state is shared or centralized updates and tooling are useful.
(This article was written by one of our staff writers, Nathan Sterling. Visit our Meet the Team page.)
