0
# Connect Higher-Order Component
1
2
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.
3
4
## Capabilities
5
6
### Connect Function
7
8
Higher-order component factory that connects React components to Redux store by injecting state and dispatch as props.
9
10
```typescript { .api }
11
/**
12
* Connect function overloads for different usage patterns
13
*/
14
interface Connect<DefaultState = unknown> {
15
// No arguments - just adds dispatch prop
16
(): InferableComponentEnhancer<DispatchProp>;
17
18
// mapStateToProps only
19
<TStateProps = {}, no_dispatch = {}, TOwnProps = {}, State = DefaultState>(
20
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>
21
): InferableComponentEnhancerWithProps<TStateProps & DispatchProp, TOwnProps>;
22
23
// mapDispatchToProps only (function)
24
<no_state = {}, TDispatchProps = {}, TOwnProps = {}>(
25
mapStateToProps: null | undefined,
26
mapDispatchToProps: MapDispatchToPropsFunction<TDispatchProps, TOwnProps>
27
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
28
29
// mapDispatchToProps only (object)
30
<no_state = {}, TDispatchProps = {}, TOwnProps = {}>(
31
mapStateToProps: null | undefined,
32
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>
33
): InferableComponentEnhancerWithProps<ResolveThunks<TDispatchProps>, TOwnProps>;
34
35
// Both mapStateToProps and mapDispatchToProps (function)
36
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = DefaultState>(
37
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
38
mapDispatchToProps: MapDispatchToPropsFunction<TDispatchProps, TOwnProps>
39
): InferableComponentEnhancerWithProps<TStateProps & TDispatchProps, TOwnProps>;
40
41
// Both mapStateToProps and mapDispatchToProps (object)
42
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = DefaultState>(
43
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
44
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>
45
): InferableComponentEnhancerWithProps<TStateProps & ResolveThunks<TDispatchProps>, TOwnProps>;
46
47
// All three arguments
48
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, TMergedProps = {}, State = DefaultState>(
49
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
50
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
51
mergeProps: MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps>
52
): InferableComponentEnhancerWithProps<TMergedProps, TOwnProps>;
53
54
// All four arguments
55
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, TMergedProps = {}, State = DefaultState>(
56
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
57
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
58
mergeProps: MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps>,
59
options: ConnectOptions<State, TStateProps, TOwnProps, TMergedProps>
60
): InferableComponentEnhancerWithProps<TMergedProps, TOwnProps>;
61
}
62
63
const connect: Connect;
64
65
type InferableComponentEnhancer<TInjectedProps> =
66
InferableComponentEnhancerWithProps<TInjectedProps, {}>;
67
68
type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> =
69
<C extends ComponentType<Matching<TInjectedProps, GetProps<C>>>>(
70
component: C
71
) => ConnectedComponent<C, Mapped<DistributiveOmit<GetLibraryManagedProps<C>, keyof Shared<TInjectedProps, GetLibraryManagedProps<C>>> & TNeedsProps & ConnectPropsMaybeWithoutContext<TNeedsProps & GetProps<C>>>>;
72
73
type ConnectedComponent<C extends ComponentType<any>, P> =
74
FunctionComponent<P> & NonReactStatics<C> & { WrappedComponent: C };
75
```
76
77
**Basic Usage:**
78
79
```typescript
80
import { connect } from "react-redux";
81
82
// Class component
83
class TodoList extends Component<Props> {
84
render() {
85
const { todos, addTodo } = this.props;
86
return (
87
<div>
88
{todos.map(todo => <div key={todo.id}>{todo.text}</div>)}
89
<button onClick={() => addTodo("New todo")}>Add</button>
90
</div>
91
);
92
}
93
}
94
95
// Connect to Redux
96
const mapStateToProps = (state: RootState) => ({
97
todos: state.todos
98
});
99
100
const mapDispatchToProps = {
101
addTodo: (text: string) => ({ type: "ADD_TODO", payload: text })
102
};
103
104
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
105
```
106
107
### Map State to Props
108
109
Functions that define how Redux state maps to component props.
110
111
```typescript { .api }
112
/**
113
* Function that maps Redux state to component props
114
*/
115
type MapStateToProps<TStateProps, TOwnProps, State> =
116
(state: State, ownProps: TOwnProps) => TStateProps;
117
118
/**
119
* Factory function that creates a mapStateToProps function
120
*/
121
type MapStateToPropsFactory<TStateProps, TOwnProps, State> =
122
(initialState: State, ownProps: TOwnProps) => MapStateToProps<TStateProps, TOwnProps, State>;
123
124
/**
125
* Parameter type for mapStateToProps - can be function or factory
126
*/
127
type MapStateToPropsParam<TStateProps, TOwnProps, State> =
128
MapStateToPropsFactory<TStateProps, TOwnProps, State> |
129
MapStateToProps<TStateProps, TOwnProps, State> |
130
null |
131
undefined;
132
```
133
134
**Usage Examples:**
135
136
```typescript
137
// Simple state mapping
138
const mapStateToProps = (state: RootState) => ({
139
user: state.auth.user,
140
isLoading: state.ui.loading
141
});
142
143
// With own props
144
const mapStateToProps = (state: RootState, ownProps: OwnProps) => ({
145
todo: state.todos.find(todo => todo.id === ownProps.todoId)
146
});
147
148
// Factory function for performance optimization
149
const makeMapStateToProps = () => {
150
const getTodosForUser = createSelector(
151
[(state: RootState) => state.todos, (state: RootState, props: Props) => props.userId],
152
(todos, userId) => todos.filter(todo => todo.userId === userId)
153
);
154
155
return (state: RootState, props: Props) => ({
156
todos: getTodosForUser(state, props)
157
});
158
};
159
```
160
161
### Map Dispatch to Props
162
163
Functions and objects that define how dispatch maps to component props.
164
165
```typescript { .api }
166
/**
167
* Function that maps dispatch to component props
168
*/
169
type MapDispatchToPropsFunction<TDispatchProps, TOwnProps> =
170
(dispatch: Dispatch<Action<string>>, ownProps: TOwnProps) => TDispatchProps;
171
172
/**
173
* Object mapping action creators to component props
174
*/
175
type MapDispatchToProps<TDispatchProps, TOwnProps> =
176
MapDispatchToPropsFunction<TDispatchProps, TOwnProps> | TDispatchProps;
177
178
/**
179
* Factory function that creates a mapDispatchToProps function
180
*/
181
type MapDispatchToPropsFactory<TDispatchProps, TOwnProps> =
182
(dispatch: Dispatch<Action<string>>, ownProps: TOwnProps) => MapDispatchToPropsFunction<TDispatchProps, TOwnProps>;
183
184
/**
185
* Parameter type for mapDispatchToProps
186
*/
187
type MapDispatchToPropsParam<TDispatchProps, TOwnProps> =
188
MapDispatchToPropsFactory<TDispatchProps, TOwnProps> |
189
MapDispatchToProps<TDispatchProps, TOwnProps>;
190
191
/**
192
* Resolves thunk action creators in dispatch props
193
*/
194
type ResolveThunks<TDispatchProps> = TDispatchProps extends { [key: string]: any }
195
? { [C in keyof TDispatchProps]: HandleThunkActionCreator<TDispatchProps[C]> }
196
: TDispatchProps;
197
```
198
199
**Usage Examples:**
200
201
```typescript
202
// Object shorthand (recommended)
203
const mapDispatchToProps = {
204
addTodo: (text: string) => ({ type: "ADD_TODO", payload: text }),
205
removeTodo: (id: number) => ({ type: "REMOVE_TODO", payload: id })
206
};
207
208
// Function form
209
const mapDispatchToProps = (dispatch: Dispatch) => ({
210
addTodo: (text: string) => dispatch({ type: "ADD_TODO", payload: text }),
211
removeTodo: (id: number) => dispatch({ type: "REMOVE_TODO", payload: id })
212
});
213
214
// With thunk actions
215
const mapDispatchToProps = {
216
fetchUser: fetchUserThunk,
217
updateUser: updateUserThunk
218
};
219
220
// Factory function
221
const makeMapDispatchToProps = () => {
222
return (dispatch: Dispatch, ownProps: Props) => ({
223
loadData: () => dispatch(fetchData(ownProps.dataId))
224
});
225
};
226
```
227
228
### Merge Props
229
230
Function that combines state props, dispatch props, and own props into final props.
231
232
```typescript { .api }
233
/**
234
* Function that merges state props, dispatch props, and own props
235
* @param stateProps - Props from mapStateToProps
236
* @param dispatchProps - Props from mapDispatchToProps
237
* @param ownProps - Props passed to the connected component
238
* @returns Final props object for the wrapped component
239
*/
240
type MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps> =
241
(stateProps: TStateProps, dispatchProps: TDispatchProps, ownProps: TOwnProps) => TMergedProps;
242
```
243
244
**Usage Example:**
245
246
```typescript
247
const mergeProps = (stateProps, dispatchProps, ownProps) => ({
248
...stateProps,
249
...dispatchProps,
250
...ownProps,
251
// Custom merged prop
252
canEdit: stateProps.user.id === ownProps.itemOwnerId && stateProps.user.isLoggedIn
253
});
254
255
const ConnectedComponent = connect(
256
mapStateToProps,
257
mapDispatchToProps,
258
mergeProps
259
)(MyComponent);
260
```
261
262
### Connect Options
263
264
Configuration options for customizing connect behavior.
265
266
```typescript { .api }
267
interface ConnectOptions<State = unknown, TStateProps = {}, TOwnProps = {}, TMergedProps = {}> {
268
/** Enable ref forwarding to wrapped component */
269
forwardRef?: boolean;
270
/** Custom context to use instead of ReactReduxContext */
271
context?: typeof ReactReduxContext;
272
/** Custom equality function for state comparison */
273
areStatesEqual?: (nextState: State, prevState: State, nextOwnProps: TOwnProps, prevOwnProps: TOwnProps) => boolean;
274
/** Custom equality function for own props comparison */
275
areOwnPropsEqual?: (nextOwnProps: TOwnProps, prevOwnProps: TOwnProps) => boolean;
276
/** Custom equality function for state props comparison */
277
areStatePropsEqual?: (nextStateProps: TStateProps, prevStateProps: TStateProps) => boolean;
278
/** Custom equality function for merged props comparison */
279
areMergedPropsEqual?: (nextMergedProps: TMergedProps, prevMergedProps: TMergedProps) => boolean;
280
}
281
```
282
283
**Usage Example:**
284
285
```typescript
286
const options = {
287
forwardRef: true,
288
areStatesEqual: (next, prev) => next.version === prev.version,
289
areOwnPropsEqual: (next, prev) => next.id === prev.id
290
};
291
292
const ConnectedComponent = connect(
293
mapStateToProps,
294
mapDispatchToProps,
295
null,
296
options
297
)(MyComponent);
298
299
// Access original component through ref
300
const ref = useRef();
301
<ConnectedComponent ref={ref} />
302
// ref.current points to MyComponent instance
303
```
304
305
## Advanced Usage
306
307
### ConnectedProps Type Helper
308
309
Extract props type from a connected component for type reuse.
310
311
```typescript { .api }
312
/**
313
* Extracts the props type from a connected component
314
*/
315
type ConnectedProps<TConnector> = TConnector extends InferableComponentEnhancerWithProps<infer TInjectedProps, any>
316
? unknown extends TInjectedProps
317
? TConnector extends InferableComponentEnhancer<infer TInjectedProps>
318
? TInjectedProps
319
: never
320
: TInjectedProps
321
: never;
322
```
323
324
**Usage Example:**
325
326
```typescript
327
const connector = connect(mapStateToProps, mapDispatchToProps);
328
type PropsFromRedux = ConnectedProps<typeof connector>;
329
330
// Use in component definition
331
const MyComponent: React.FC<PropsFromRedux & OwnProps> = (props) => {
332
// props includes both Redux and own props
333
};
334
335
export default connector(MyComponent);
336
```
337
338
### Custom Context Usage
339
340
Use connect with custom React context for multiple stores.
341
342
```typescript
343
import { createContext } from "react";
344
import { connect } from "react-redux";
345
346
const CustomContext = createContext(null);
347
348
const ConnectedComponent = connect(
349
mapStateToProps,
350
mapDispatchToProps,
351
null,
352
{ context: CustomContext }
353
)(MyComponent);
354
355
// Provide custom context
356
<Provider store={customStore} context={CustomContext}>
357
<ConnectedComponent />
358
</Provider>
359
```
360
361
## Migration from Connect to Hooks
362
363
While connect is fully supported, hooks provide a more modern and flexible API:
364
365
```typescript
366
// Connect approach
367
const mapStateToProps = (state: RootState) => ({
368
todos: state.todos,
369
user: state.user
370
});
371
372
const mapDispatchToProps = {
373
addTodo,
374
removeUser
375
};
376
377
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
378
379
// Hooks approach
380
function TodoList() {
381
const todos = useSelector((state: RootState) => state.todos);
382
const user = useSelector((state: RootState) => state.user);
383
const dispatch = useDispatch();
384
385
const handleAddTodo = (text: string) => dispatch(addTodo(text));
386
const handleRemoveUser = (id: number) => dispatch(removeUser(id));
387
388
return (
389
// Component JSX
390
);
391
}
392
```