React's functional components used to require classes for state management. Hooks changed that fundamentally. A new tutorial from ReactGo walks through connecting Redux state and dispatching actions using the useSelector and useDispatch hooks.
The guide builds a simple counter app demonstrating the complete Redux integration pattern, from initial store setup to component binding. If you've been putting off learning Redux hooks, this walkthrough makes the concepts approachable.
Setting Up the Redux Store
The Redux store holds your entire application state in a single JavaScript object. This centralization makes tracking changes straightforward and enables powerful developer tools for debugging.
The tutorial creates a reducer function with action types for incrementing and decrementing. The reducer receives the current state and an action object, then returns the new state based on the action type. Switch statements are the conventional pattern here, matching each action type to its corresponding state transformation.
Once the reducer exists, the store gets created with createStore and wrapped around the app using the Provider component from react-redux. This Provider sits at the app root and makes the Redux store available to all components beneath it.
Reading State with useSelector
The useSelector hook accesses Redux state from within a functional component. Pass a selector function that receives the entire store state and returns the specific data your component needs. In the tutorial, this looks like selecting the counter.num property from the overall state tree.
The hook also subscribes your component to store updates automatically. When the selected slice changes, React re-renders the component. When it stays the same, no re-render occurs. This optimization prevents unnecessary work.
The tutorial demonstrates accessing the full state object, but selectors typically extract a specific nested value. The pattern scales to any depth in your state tree.
Dispatching Actions with useDispatch
The useDispatch hook returns the Redux store's dispatch function. Call it with an action object to trigger state changes. The action object must include a type property identifying which reducer case should execute.
The tutorial shows dispatching INCREMENT actions with a step value when users click a button. The reducer receives this action, matches the type, and updates state accordingly. The counter increments by the specified step amount.
Dispatching is synchronous by default. For asynchronous operations like API calls, you would add Redux middleware such as redux-thunk or redux-saga, but those patterns extend beyond the tutorial's scope.
Why This Matters
The hooks API represents a significant improvement over the original connect Higher Order Component approach. The old pattern required wrapping components, defining mapStateToProps and mapDispatchToProps functions, and managing prop passing through multiple layers.
With hooks, the code is shorter, easier to read, and feels more natural in functional components. You declare what you need at the top of your component and use it directly. No wrapper components, no prop drilling.
The counter example is simple but demonstrates the core pattern cleanly. Real applications have multiple reducers combined with combineReducers and selectors that pull deeply nested data. The same hooks work regardless of complexity.
A Worked Example
Say you are building an Android app with a web admin panel in React. Your users table state lives in Redux. A UserList component uses useSelector to access the users array. A UserRow component might use useSelector to access a single user by ID and useDispatch to update that user's role.
When an admin clicks delete, useDispatch fires a DELETE_USER action. The reducer removes the user from state. Both components automatically re-render with the updated list because they subscribe to the relevant state slices. This predictability makes debugging easier.
What to Watch Next
The React Redux hooks make state management cleaner in functional components. The Provider wrapper handles initialization once at the app root, then useSelector and useDispatch handle everything else.
If you are starting a new project, hooks are the recommended approach. If you are maintaining older code with connect, consider gradually migrating components as you touch them.
Key takeaways
- Provider wraps the entire app to make the Redux store available to all components
- UseSelector subscribes components to specific state slices and triggers re-renders on changes
- UseDispatch returns the dispatch function for triggering actions that update state
- Actions are plain objects with a type property and optional payload data
- The hooks API simplifies code compared to the older connect Higher Order Component pattern
- Reducers use switch statements to match action types and return new state
Frequently asked questions
Can I use useSelector and useDispatch together in the same component?
Yes. Most components that read state also need to dispatch actions. Import both hooks from react-redux and use them side by side. This is the standard pattern for components that both display data and respond to user interactions.
Does useSelector cause unnecessary re-renders?
It triggers re-renders only when the selected state slice actually changes. Using shallow equality checks for objects and arrays prevents redundant renders. For expensive computations, consider using useMemo with the selector result.
What is the difference between useSelector and mapStateToProps?
They serve the same purpose of extracting state for a component. UseSelector is a hook that works directly inside functional components, while mapStateToProps requires the connect Higher Order Component wrapper. Hooks are generally preferred for new code.
Can I access multiple state slices with one useSelector call?
Yes. Return an object containing all the slices you need in a single selector function. Alternatively, use multiple useSelector calls, each subscribing to only the slice that component actually needs.
Is Redux still necessary with React Context available?
For small applications with simple shared state, Context works fine. For larger applications with complex state, multiple actions, and intricate relationships between state slices, Redux provides better debugging tools like time-travel, solid middleware support, and a proven architecture that scales better.