0% completed
Now that we have learned about what Redux is, the benefits it offers in a React application, and the best use cases for it, we will now focus on the fundamental parts of Redux's architecture.
In this lesson, we will be taking a deep dive into actions in Redux. By the end of this lesson, you will have a good knowledge on their functions and how to use them in your React apps.
Actions are JavaScript objects that describe a change or event in your application's state. They serve as the sole way to communicate with the Redux store, instructing it about what type of operation is needed.
Actions are pure objects that must contain at least a type property, which is a string that describes the action. Optionally, they can contain additional data (called payload) that provides more context for the change.
An action is typically structured like this:
{ type: 'ACTION_TYPE', payload: data, // optional }
Let’s consider an example of a simple to-do app, where you want to manage actions related to adding, removing, and toggling the completion status of to-do items.
Action to Add a Todo:
const addTodo = (text) => { return { type: 'ADD_TODO', payload: { text: text, completed: false } }; };
Here, the action is describing the addition of a new to-do item. The payload
contains the text of the new to-do and the initial state of whether the to-do is completed (which is false
).
Example of how you might dispatch this action:
dispatch(addTodo("Learn Redux"));
Action to Remove a Todo:
const removeTodo = (id) => { return { type: 'REMOVE_TODO', payload: { id: id } }; };
This action is used to remove a to-do item by its id
. The id
is passed as part of the action's payload
.
Example of dispatching this action:
dispatch(removeTodo(2)); // Removes the to-do with id 2
Action to Toggle a Todo’s Completion:
const toggleTodo = (id) => { return { type: 'TOGGLE_TODO', payload: { id: id } }; };
This action toggles the completed
state of a to-do item by its id
. The payload
here contains the id
of the to-do to be toggled.
Example of dispatching this action:
dispatch(toggleTodo(1)); // Toggles the to-do with id 1
In practice, actions are often defined using action creators. These are functions that return action objects. They provide a cleaner and more maintainable way to create actions, especially when passing dynamic data like in the examples above.
For instance:
const addTodo = (text) => ({ type: 'ADD_TODO', payload: { text, completed: false } });
Using action creators makes it easier to modify actions in one place rather than throughout your codebase.
To avoid errors caused by typos in action type strings, it's common to define action types as constants. This improves maintainability, especially in larger projects.
// actionTypes.js export const ADD_TODO = 'ADD_TODO'; export const REMOVE_TODO = 'REMOVE_TODO'; export const TOGGLE_TODO = 'TOGGLE_TODO'; // actions.js import { ADD_TODO, REMOVE_TODO, TOGGLE_TODO } from './actionTypes'; export const addTodo = (text) => ({ type: ADD_TODO, payload: { text, completed: false } });
When an action is dispatched, it is sent to a reducer function in Redux, which updates the state based on the action's type and payload. For example, a reducer for the to-do app could look like this:
const todosReducer = (state = [], action) => { switch (action.type) { case 'ADD_TODO': return [ ...state, { text: action.payload.text, completed: action.payload.completed } ]; case 'REMOVE_TODO': return state.filter(todo => todo.id !== action.payload.id); case 'TOGGLE_TODO': return state.map(todo => todo.id === action.payload.id ? { ...todo, completed: !todo.completed } : todo ); default: return state; } };
In conclusion, actions play a crucial role in Redux by defining the type of operation that should occur, and they help ensure that state updates happen in a predictable and controlled manner.
.....
.....
.....