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.

June 27, 20263 min read1 / 4

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:

JSX
import { connect } from 'react-redux';

Wrap the default export at the bottom of the component file:

JSX
export default connect()(Tasks);

connect() called with no arguments gives the component one prop: dispatch. That is enough to dispatch actions:

JSX
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():

JavaScript
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.

JSX
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:

JSX
// Dangerous: re-renders on every dispatch useEffect(() => { dispatch(actions.fetchTasks()); }, [props]); // props is a new object every render

Fix by destructuring dispatch from props and using only that as the dependency:

JSX
const { dispatch } = props; useEffect(() => { dispatch(actions.fetchTasks()); }, [dispatch]); // stable reference, runs only once

connect() vs hooks

connect()useSelector / useDispatch
Available sinceReact-Redux 5React-Redux 7
StyleHOC (wraps component)Hook (called inside component)
State accessmapStateToProps → propsuseSelector(selector)
Dispatch accessprops.dispatchuseDispatch()
VerbosityMore boilerplateLess 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.

connect() as an intermediate component between Provider and your component Expandconnect() as an intermediate component between Provider and your component

The Essentials

  1. connect()(Component) wraps your component and injects dispatch as a prop. You can dispatch any action creator through props.dispatch without calling useDispatch().
  2. mapStateToProps(state) returns an object whose properties become additional props. { tasks: state.tasks } gives the component props.tasks, equivalent to useSelector((s) => s.tasks).
  3. Hooks are preferred for new code. connect() is correct to use in existing projects. If you see it in a codebase, read the mapStateToProps function to understand what state the component receives.

Further Reading and Watching