Official React bindings for Redux state management with hooks and higher-order components
—
Legacy API for connecting React components to Redux store using higher-order component pattern. While hooks are the recommended modern approach, connect remains fully supported for class components and complex scenarios.
Higher-order component factory that connects React components to Redux store by injecting state and dispatch as props.
/**
* Connect function overloads for different usage patterns
*/
interface Connect<DefaultState = unknown> {
// No arguments - just adds dispatch prop
(): InferableComponentEnhancer<DispatchProp>;
// mapStateToProps only
<TStateProps = {}, no_dispatch = {}, TOwnProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>
): InferableComponentEnhancerWithProps<TStateProps & DispatchProp, TOwnProps>;
// mapDispatchToProps only (function)
<no_state = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: MapDispatchToPropsFunction<TDispatchProps, TOwnProps>
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
// mapDispatchToProps only (object)
<no_state = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>
): InferableComponentEnhancerWithProps<ResolveThunks<TDispatchProps>, TOwnProps>;
// Both mapStateToProps and mapDispatchToProps (function)
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsFunction<TDispatchProps, TOwnProps>
): InferableComponentEnhancerWithProps<TStateProps & TDispatchProps, TOwnProps>;
// Both mapStateToProps and mapDispatchToProps (object)
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>
): InferableComponentEnhancerWithProps<TStateProps & ResolveThunks<TDispatchProps>, TOwnProps>;
// All three arguments
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, TMergedProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
mergeProps: MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps>
): InferableComponentEnhancerWithProps<TMergedProps, TOwnProps>;
// All four arguments
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, TMergedProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
mergeProps: MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps>,
options: ConnectOptions<State, TStateProps, TOwnProps, TMergedProps>
): InferableComponentEnhancerWithProps<TMergedProps, TOwnProps>;
}
const connect: Connect;
type InferableComponentEnhancer<TInjectedProps> =
InferableComponentEnhancerWithProps<TInjectedProps, {}>;
type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> =
<C extends ComponentType<Matching<TInjectedProps, GetProps<C>>>>(
component: C
) => ConnectedComponent<C, Mapped<DistributiveOmit<GetLibraryManagedProps<C>, keyof Shared<TInjectedProps, GetLibraryManagedProps<C>>> & TNeedsProps & ConnectPropsMaybeWithoutContext<TNeedsProps & GetProps<C>>>>;
type ConnectedComponent<C extends ComponentType<any>, P> =
FunctionComponent<P> & NonReactStatics<C> & { WrappedComponent: C };Basic Usage:
import { connect } from "react-redux";
// Class component
class TodoList extends Component<Props> {
render() {
const { todos, addTodo } = this.props;
return (
<div>
{todos.map(todo => <div key={todo.id}>{todo.text}</div>)}
<button onClick={() => addTodo("New todo")}>Add</button>
</div>
);
}
}
// Connect to Redux
const mapStateToProps = (state: RootState) => ({
todos: state.todos
});
const mapDispatchToProps = {
addTodo: (text: string) => ({ type: "ADD_TODO", payload: text })
};
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);Functions that define how Redux state maps to component props.
/**
* Function that maps Redux state to component props
*/
type MapStateToProps<TStateProps, TOwnProps, State> =
(state: State, ownProps: TOwnProps) => TStateProps;
/**
* Factory function that creates a mapStateToProps function
*/
type MapStateToPropsFactory<TStateProps, TOwnProps, State> =
(initialState: State, ownProps: TOwnProps) => MapStateToProps<TStateProps, TOwnProps, State>;
/**
* Parameter type for mapStateToProps - can be function or factory
*/
type MapStateToPropsParam<TStateProps, TOwnProps, State> =
MapStateToPropsFactory<TStateProps, TOwnProps, State> |
MapStateToProps<TStateProps, TOwnProps, State> |
null |
undefined;Usage Examples:
// Simple state mapping
const mapStateToProps = (state: RootState) => ({
user: state.auth.user,
isLoading: state.ui.loading
});
// With own props
const mapStateToProps = (state: RootState, ownProps: OwnProps) => ({
todo: state.todos.find(todo => todo.id === ownProps.todoId)
});
// Factory function for performance optimization
const makeMapStateToProps = () => {
const getTodosForUser = createSelector(
[(state: RootState) => state.todos, (state: RootState, props: Props) => props.userId],
(todos, userId) => todos.filter(todo => todo.userId === userId)
);
return (state: RootState, props: Props) => ({
todos: getTodosForUser(state, props)
});
};Functions and objects that define how dispatch maps to component props.
/**
* Function that maps dispatch to component props
*/
type MapDispatchToPropsFunction<TDispatchProps, TOwnProps> =
(dispatch: Dispatch<Action<string>>, ownProps: TOwnProps) => TDispatchProps;
/**
* Object mapping action creators to component props
*/
type MapDispatchToProps<TDispatchProps, TOwnProps> =
MapDispatchToPropsFunction<TDispatchProps, TOwnProps> | TDispatchProps;
/**
* Factory function that creates a mapDispatchToProps function
*/
type MapDispatchToPropsFactory<TDispatchProps, TOwnProps> =
(dispatch: Dispatch<Action<string>>, ownProps: TOwnProps) => MapDispatchToPropsFunction<TDispatchProps, TOwnProps>;
/**
* Parameter type for mapDispatchToProps
*/
type MapDispatchToPropsParam<TDispatchProps, TOwnProps> =
MapDispatchToPropsFactory<TDispatchProps, TOwnProps> |
MapDispatchToProps<TDispatchProps, TOwnProps>;
/**
* Resolves thunk action creators in dispatch props
*/
type ResolveThunks<TDispatchProps> = TDispatchProps extends { [key: string]: any }
? { [C in keyof TDispatchProps]: HandleThunkActionCreator<TDispatchProps[C]> }
: TDispatchProps;Usage Examples:
// Object shorthand (recommended)
const mapDispatchToProps = {
addTodo: (text: string) => ({ type: "ADD_TODO", payload: text }),
removeTodo: (id: number) => ({ type: "REMOVE_TODO", payload: id })
};
// Function form
const mapDispatchToProps = (dispatch: Dispatch) => ({
addTodo: (text: string) => dispatch({ type: "ADD_TODO", payload: text }),
removeTodo: (id: number) => dispatch({ type: "REMOVE_TODO", payload: id })
});
// With thunk actions
const mapDispatchToProps = {
fetchUser: fetchUserThunk,
updateUser: updateUserThunk
};
// Factory function
const makeMapDispatchToProps = () => {
return (dispatch: Dispatch, ownProps: Props) => ({
loadData: () => dispatch(fetchData(ownProps.dataId))
});
};Function that combines state props, dispatch props, and own props into final props.
/**
* Function that merges state props, dispatch props, and own props
* @param stateProps - Props from mapStateToProps
* @param dispatchProps - Props from mapDispatchToProps
* @param ownProps - Props passed to the connected component
* @returns Final props object for the wrapped component
*/
type MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps> =
(stateProps: TStateProps, dispatchProps: TDispatchProps, ownProps: TOwnProps) => TMergedProps;Usage Example:
const mergeProps = (stateProps, dispatchProps, ownProps) => ({
...stateProps,
...dispatchProps,
...ownProps,
// Custom merged prop
canEdit: stateProps.user.id === ownProps.itemOwnerId && stateProps.user.isLoggedIn
});
const ConnectedComponent = connect(
mapStateToProps,
mapDispatchToProps,
mergeProps
)(MyComponent);Configuration options for customizing connect behavior.
interface ConnectOptions<State = unknown, TStateProps = {}, TOwnProps = {}, TMergedProps = {}> {
/** Enable ref forwarding to wrapped component */
forwardRef?: boolean;
/** Custom context to use instead of ReactReduxContext */
context?: typeof ReactReduxContext;
/** Custom equality function for state comparison */
areStatesEqual?: (nextState: State, prevState: State, nextOwnProps: TOwnProps, prevOwnProps: TOwnProps) => boolean;
/** Custom equality function for own props comparison */
areOwnPropsEqual?: (nextOwnProps: TOwnProps, prevOwnProps: TOwnProps) => boolean;
/** Custom equality function for state props comparison */
areStatePropsEqual?: (nextStateProps: TStateProps, prevStateProps: TStateProps) => boolean;
/** Custom equality function for merged props comparison */
areMergedPropsEqual?: (nextMergedProps: TMergedProps, prevMergedProps: TMergedProps) => boolean;
}Usage Example:
const options = {
forwardRef: true,
areStatesEqual: (next, prev) => next.version === prev.version,
areOwnPropsEqual: (next, prev) => next.id === prev.id
};
const ConnectedComponent = connect(
mapStateToProps,
mapDispatchToProps,
null,
options
)(MyComponent);
// Access original component through ref
const ref = useRef();
<ConnectedComponent ref={ref} />
// ref.current points to MyComponent instanceExtract props type from a connected component for type reuse.
/**
* Extracts the props type from a connected component
*/
type ConnectedProps<TConnector> = TConnector extends InferableComponentEnhancerWithProps<infer TInjectedProps, any>
? unknown extends TInjectedProps
? TConnector extends InferableComponentEnhancer<infer TInjectedProps>
? TInjectedProps
: never
: TInjectedProps
: never;Usage Example:
const connector = connect(mapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;
// Use in component definition
const MyComponent: React.FC<PropsFromRedux & OwnProps> = (props) => {
// props includes both Redux and own props
};
export default connector(MyComponent);Use connect with custom React context for multiple stores.
import { createContext } from "react";
import { connect } from "react-redux";
const CustomContext = createContext(null);
const ConnectedComponent = connect(
mapStateToProps,
mapDispatchToProps,
null,
{ context: CustomContext }
)(MyComponent);
// Provide custom context
<Provider store={customStore} context={CustomContext}>
<ConnectedComponent />
</Provider>While connect is fully supported, hooks provide a more modern and flexible API:
// Connect approach
const mapStateToProps = (state: RootState) => ({
todos: state.todos,
user: state.user
});
const mapDispatchToProps = {
addTodo,
removeUser
};
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
// Hooks approach
function TodoList() {
const todos = useSelector((state: RootState) => state.todos);
const user = useSelector((state: RootState) => state.user);
const dispatch = useDispatch();
const handleAddTodo = (text: string) => dispatch(addTodo(text));
const handleRemoveUser = (id: number) => dispatch(removeUser(id));
return (
// Component JSX
);
}Install with Tessl CLI
npx tessl i tessl/npm-react-redux