useDispatch: Creating and Deleting Tasks with Redux

useDispatch returns the Redux store's dispatch function. Use it to trigger createTask and deleteTask from the Tasks component, and add a utility function to format dates for display.

June 27, 20263 min read2 / 3

The task list renders from Redux state. The UI sees the data. What does not work yet: the Save and Delete buttons have no effect on the store.

useDispatch is the hook that connects button clicks to Redux actions.

Importing useDispatch

JSX
import { useDispatch } from 'react-redux'; const dispatch = useDispatch();

Call useDispatch() once at the top of the component. It returns the store's dispatch function. Every dispatch(actionCreator(...)) call flows to the reducer.

Also import the action creators from the barrel file we created:

JSX
import actions from '../../actions';

Local State for the Form

The task form needs two input values: task title and date/time. These belong in local useState, not Redux. They are needed only inside Tasks while the form is open.

JSX
const [taskTitle, setTaskTitle] = useState(''); const [dateTime, setDateTime] = useState('');

Bind both to their inputs with value and onChange:

JSX
<input type="text" value={taskTitle} onChange={(e) => setTaskTitle(e.target.value)} /> <input type="datetime-local" value={dateTime} onChange={(e) => setDateTime(e.target.value)} />

When to use Redux vs useState: if a piece of state is only needed by one component and no other component will ever read it, keep it in useState. Text input values while typing are a classic example. The finished task object, once saved, belongs in Redux so it can be read from anywhere.

Dispatching CREATE_TASK

Update onSaveClick to dispatch the action:

JSX
function onSaveClick() { const newTask = { id: Math.floor(Math.random() * 1_000_000), taskTitle, dateTime, }; dispatch(actions.createTask(newTask)); setTaskTitle(''); setDateTime(''); setIsNewTaskOpen(false); }

Math.floor(Math.random() * 1_000_000) generates a random integer id. In a production app that talks to a database, the server generates the id. This local approach is for development only.

After dispatch, both input fields reset to empty and the form closes. The component re-renders because useSelector detects the new task in the store.

Dispatching DELETE_TASK

Add an onDeleteClick handler and wire it to the delete button:

JSX
function onDeleteClick(task) { if (window.confirm('Delete this task?')) { dispatch(actions.deleteTask(task.id)); } }

In the task list, pass the current task to the handler:

JSX
<button className="icon-button" onClick={() => onDeleteClick(task)} > &times; </button>

The action creator receives the task id, returns { type: DELETE_TASK, payload: taskId }, and the reducer filters it out of state. The task disappears from the list immediately.

Formatting Dates for Display

Raw datetime-local values display as 2026-07-01T09:00, which is not readable. Create a utility function in src/utils/index.js:

JavaScript
export function toDisplayDateFormat(dateString) { const date = new Date(dateString); const day = date.getDate(); const month = date.toLocaleString('default', { month: 'short' }); const year = date.getFullYear(); const hours = date.getHours().toString().padStart(2, '0'); const mins = date.getMinutes().toString().padStart(2, '0'); return `${day} ${month} ${year}, ${hours}:${mins}`; }

Import it in Tasks.js and use it while rendering:

JSX
import { toDisplayDateFormat } from '../../utils'; // inside the task map: <div className="task-subtitle">{toDisplayDateFormat(task.dateTime)}</div>

The utils/ folder exists for exactly this reason: reusable logic that belongs to no single component.

useDispatch triggering action creators that flow through the reducer to update the store ExpanduseDispatch triggering action creators that flow through the reducer to update the store

The Essentials

  1. useDispatch() returns the store's dispatch function. Call it once at the top of the component. Pass action objects created by action creators to it.
  2. Form input state stays in useState. taskTitle and dateTime are local to the Tasks component during input. Once saved, the structured task object moves into Redux state via dispatch.
  3. The utils/ folder handles reusable logic. Date formatting has no business in a component. Extracting it to utils/index.js keeps components focused on rendering.

Further Reading and Watching

Practice what you just read.

Implement useDispatch
1 exercise