The connect() Function: Redux Before Hooks
connect() is the React-Redux API used before hooks existed. Real-world projects built before 2017 use it. Understanding it lets you work in older codebases without rewriting everything.
The useSelector and useDispatch hooks are the current way to interact with the Redux store. They were introduced in React-Redux 7.0. Any project built before that, including many that were not immediately migrated, uses connect() instead.
You will encounter connect() in real codebases. This post covers what it does and how to read it.
What connect() Does
connect() is a function that wraps your component and gives it access to the Redux store through props. Instead of calling useSelector() and useDispatch() inside the component, the state and dispatch arrive as props.tasks and props.dispatch.
The conceptual model: connect() creates an invisible parent component that subscribes to the store and passes the relevant state slices and dispatch down to your component as props.
Basic Usage
Import connect from react-redux:
import { connect } from 'react-redux';Wrap the default export at the bottom of the component file:
export default connect()(Tasks);connect() called with no arguments gives the component one prop: dispatch. That is enough to dispatch actions:
const { dispatch } = props;
dispatch(actions.createTask(newTask));
dispatch(actions.deleteTask(task.id));Reading State with mapStateToProps
To read state, pass a mapStateToProps function as the first argument to connect():
function mapStateToProps(state) {
return {
tasks: state.tasks,
};
}
export default connect(mapStateToProps)(Tasks);mapStateToProps receives the full Redux state and returns a plain object. Every property in that object becomes a prop on the component. Inside Tasks, access the task data as props.tasks.
const tasks = props.tasks;
const filteredTasks = (tasks.data || []).filter(...);This is equivalent to const tasks = useSelector((state) => state.tasks). Same result, older syntax.
The Infinite Re-render Trap
When you pass props as a useEffect dependency, the effect fires on every render because any prop change triggers a new props object reference:
// Dangerous: re-renders on every dispatch
useEffect(() => {
dispatch(actions.fetchTasks());
}, [props]); // props is a new object every renderFix by destructuring dispatch from props and using only that as the dependency:
const { dispatch } = props;
useEffect(() => {
dispatch(actions.fetchTasks());
}, [dispatch]); // stable reference, runs only onceconnect() vs hooks
connect() | useSelector / useDispatch | |
|---|---|---|
| Available since | React-Redux 5 | React-Redux 7 |
| Style | HOC (wraps component) | Hook (called inside component) |
| State access | mapStateToProps → props | useSelector(selector) |
| Dispatch access | props.dispatch | useDispatch() |
| Verbosity | More boilerplate | Less boilerplate |
For new code, hooks are the official recommendation. For existing code using connect(), there is no urgency to migrate. Both APIs are supported and produce identical behavior.
Expandconnect() as an intermediate component between Provider and your component
The Essentials
connect()(Component)wraps your component and injectsdispatchas a prop. You can dispatch any action creator throughprops.dispatchwithout callinguseDispatch().mapStateToProps(state)returns an object whose properties become additional props.{ tasks: state.tasks }gives the componentprops.tasks, equivalent touseSelector((s) => s.tasks).- Hooks are preferred for new code.
connect()is correct to use in existing projects. If you see it in a codebase, read themapStateToPropsfunction to understand what state the component receives.
Further Reading and Watching
- React-Redux connect() API docs: complete reference including
mapDispatchToProps - Why React-Redux hooks over connect: official reasoning for the API change
components/tasks/Tasks.json GitHub: the hooks-based version of the same component for direct comparison with the connect() pattern shown above
Keep reading