Skip to content

Commit 876e4e8

Browse files
committed
Update doc content for Flow annotating connect
- Remove use case of `$Diff` - Put a couple notes on recommended usage of exact objects
1 parent 7df6a0a commit 876e4e8

File tree

2 files changed

+256
-100
lines changed

2 files changed

+256
-100
lines changed

docs/using-react-redux/annotating-connected-components-with-flow.md

Lines changed: 128 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,104 @@ In general, to make Flow happy with connect after 0.85 is a two-phase fix. First
1818

1919
## Fixing the “implicitly instantiated” errors at calls of `connect`
2020

21-
To begin, you need:
21+
> **Note:** We need `React.AbstractComponent` from Flow v0.89+
2222
23-
- Flow upgraded to v0.89+
24-
- [Newest Flow Typed library definition for React Redux](https://github.com/flow-typed/flow-typed/blob/master/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/react-redux_v5.x.x.js)
23+
### Annotating at function return
2524

26-
We include three major use cases for annotating `connect` with Flow:
25+
The easiest way to annotate connected components is to annotate at function call return. To do this, we need to know to types of props in our components:
26+
27+
- `OwnProps`: likely contain or equal to what you need as the second parameter to `mapStateToProps`. If there are props that are not used by `mapStateToProps`, i.e., the props that "pass through", include them here in `OwnProps` as well
28+
- `Props`: `OwnProps` plus the props passed in by `mapStateToProps` and `mapDispatchToProps`
29+
30+
> **Note:** Inexact objects don't spread nor `$Diff` very well. It is strongly recommended that you use exact objects for connected components all the time.
31+
32+
```js
33+
type OwnProps = {|
34+
passthrough: string,
35+
forMapStateToProps: string
36+
|}
37+
38+
type Props = {|
39+
...OwnProps,
40+
fromMapStateToProps: string,
41+
dispatch1: () => void
42+
|}
43+
```
44+
45+
With `OwnProps` and `Props` in figured out, we are now ready to annotate the connected components.
46+
47+
In _component definition_, annotate the props with `Props`. The component will have access to all the injected props from `connect`:
48+
49+
```jsx
50+
import * as React from 'react'
51+
52+
const MyComponent = (props: Props) => (
53+
<div onClick={props.dispatch1}>
54+
{props.passthrough}
55+
{props.fromMapStateToProps}
56+
</div>
57+
)
58+
```
59+
60+
When we export, this is also when we normally call `connect`, annotate the exported component with _just_ `OwnProps`:
61+
62+
```jsx
63+
import * as React from 'react'
64+
65+
// const MyComponent = ...
66+
67+
export default (connect(
68+
mapStateToProps,
69+
mapDispatchToProps
70+
)(MyComponent): React.AbstractComponent<OwnProps>)
71+
```
72+
73+
### Annotating by providing explicit type parameters
74+
75+
We may also annotate connected components by providing explicit type parameters at call of `connect` with the help of the [newest Flow Typed library definition for React Redux](https://github.com/flow-typed/flow-typed/blob/master/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/react-redux_v5.x.x.js). Note that this will also require Flow v0.89+.
76+
77+
The Flow Typed library definition declares `connect` as follows:
78+
79+
```js
80+
declare export function connect<-P, -OP, -SP, -DP, -S, -D>(
81+
mapStateToProps?: null | void,
82+
mapDispatchToProps?: null | void,
83+
mergeProps?: null | void,
84+
options?: ?Options<S, OP, {||}, MergeOP<OP, D>>
85+
): Connector<P, OP, MergeOP<OP, D>>
86+
```
87+
88+
The libdef also contains a [glossary of the abbreviations](https://github.com/flow-typed/flow-typed/blob/master/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/react-redux_v5.x.x.js#L14) which decrypts the signature to:
89+
90+
```jsx
91+
connect<Props, OwnProps, StateProps, DispatchProps, State, Dispatch>(…)
92+
```
93+
94+
For the most common ways to connect components, we won't need all of the parameters. Normally, we need only `OwnProps` and `Props` at the call of `connect`, and `State` at the definition of `mapStateToProps`.
95+
96+
We may use `_` ([what's this?](https://github.com/facebook/flow/commit/ec70da4510d3a092fa933081c083bd0e513d0518)) as placeholder at unused type parameter positions. A common `connect` call may look like this:
97+
98+
```jsx
99+
connect<Props, OwnProps, _, _, _, _>(…)
100+
```
101+
102+
We include examples for three major use cases of annotating `connect` with Flow:
27103
28104
- Connecting stateless component with `mapStateToProps`
29105
- Connecting components with `mapDispatchToProps` of action creators
30106
- Connecting components with `mapStateToProps` and `mapDispatchToProps` of action creators
31107
32-
### Connecting stateless component with `mapStateToProps`
108+
#### Connecting stateless component with `mapStateToProps`
33109
34110
```jsx
35111
type OwnProps = {|
36112
passthrough: number,
37113
forMapStateToProps: string,
38114
|};
39-
type Props = {
115+
type Props = {|
40116
...OwnProps,
41117
fromStateToProps: string
42-
};
118+
|};
43119
const Com = (props: Props) => <div>{props.passthrough} {props.fromStateToProps}</div>
44120

45121
type State = {a: number};
@@ -52,20 +128,20 @@ const mapStateToProps = (state: State, props: InputProps) => {
52128
}
53129
};
54130

55-
const Connected = connect<Props, OwnProps, _,_,_,_>(mapStateToProps)(Com);
131+
const Connected = connect<Props, OwnProps, _, _, _, _>(mapStateToProps)(Com);
56132
```
57133
58-
### Connecting components with `mapDispatchToProps` of action creators
134+
#### Connecting components with `mapDispatchToProps` of action creators
59135
60136
```jsx
61137
type OwnProps = {|
62138
passthrough: number,
63139
|};
64-
type Props = {
140+
type Props = {|
65141
...OwnProps,
66142
dispatch1: (num: number) => void,
67143
dispatch2: () => void
68-
};
144+
|};
69145
class Com extends React.Component<Props> {
70146
render() {
71147
return <div>{this.props.passthrough}</div>;
@@ -81,19 +157,19 @@ e.push(Connected);
81157
<Connected passthrough={123} />;
82158
```
83159
84-
### Connecting components with `mapStateToProps` and `mapDispatchToProps` of action creators
160+
#### Connecting components with `mapStateToProps` and `mapDispatchToProps` of action creators
85161
86162
```jsx
87163
type OwnProps = {|
88164
passthrough: number,
89165
forMapStateToProps: string
90166
|};
91-
type Props = {
167+
type Props = {|
92168
...OwnProps,
93169
dispatch1: () => void,
94170
dispatch2: () => void,
95171
fromMapStateToProps: number
96-
};
172+
|};
97173
class Com extends React.Component<Props> {
98174
render() {
99175
return <div>{this.props.passthrough}</div>;
@@ -113,65 +189,67 @@ const mapDispatchToProps = {
113189
const Connected = connect<Props, OwnProps, _, _, _, _>(mapStateToProps, mapDispatchToProps)(Com);
114190
```
115191
116-
## Annotating nested higher order components with connect
192+
### Annotating nested higher order components with connect
117193
118-
If you are at the unfortunate position where your component is wrapped with nested higher order component, it is probably more difficult to annotate by providing explicit type parameters, as doing so will probably require tediously deducing prop types at each layer:
119-
120-
```jsx
121-
import { compose } from "redux";
122-
123-
type AllProps = {/** ... */};
124-
125-
compose(
126-
connect(mapState, mapDispatch),
127-
withA<$Diff<$Diff<$Diff<AllProps, withDProps>, withCProps>, withBProps>>,
128-
withB<$Diff<$Diff<AllProps, withDProps>, withCProps>>,
129-
withC<$Diff<AllProps, withDProps>>,
130-
withD<AllProps>
131-
)(ComponentWithEverything);
132-
```
133-
134-
It is probably easier if you annotate once at file export:
194+
If you are at the unfortunate position where your component is wrapped with nested higher order component, it is probably more difficult to annotate by providing explicit type parameters, as doing so will probably require that you tediously take away props at each layer. It is agian easier to annotate at function return:
135195
136196
```jsx
197+
type OwnProps = {|
198+
passthrough: number,
199+
forMapStateToProps: string,
200+
|}
137201
type Props = {|
138-
passthrough: number
202+
...OwnProps,
203+
injectedA: string,
204+
injectedB: string,
205+
fromMapStateToProps: string,
206+
dispatch1: (number) => void,
207+
dispatch2: () => void,
139208
|}
140-
type AllProps = {
141-
// spreaded props should be exact
142-
...Props,
143-
injectedPropA: string,
144-
injectedPropB: boolean,
145-
injectedPropC: number,
146-
injectedPropD: any
147-
}
148209

149-
const Component = (props: AllProps) => {
210+
const Component = (props: Props) => { // annotate the component with all props including injected props
150211
/** ... */
151212
}
152213

214+
const mapStateToProps = (state: State, ownProps: OwnProps) => {
215+
return { fromMapStateToProps: 'str' + ownProps.forMapStateToProps },
216+
}
217+
const mapDispatchToProps = {
218+
dispatch1: number => {},
219+
dispatch2: () => {},
220+
}
221+
153222
export default (compose(
223+
connect(mapStateToProps, mapDispatchToProps),
154224
withA,
155225
withB,
156-
withC,
157-
withD
158-
)(Component): React.AbstractComponent<Props>)
226+
)(Component): React.AbstractComponent<OwnProps>) // export the connected component without injected props
159227
```
160228
161229
## Benefits of this version
162230
163-
After fixing the implicit instantiation errors, Flow now is able to report errors on type mismatches cross connected components and provide accurate error messages:
231+
After fixing the implicit instantiation errors, if your code contains mismatched types between connected components, the total number of errors may go _up_. This is the result of Flow's improved coverage. If you are using console output for the Flow errors, you may not be able to see those errors until you clear other errors. These additional errors are grouped together, all tied back to React Redux's library definition, and have friendly error messages that will pin point you to the lines of code to the errors.
164232
165233
![](https://i.imgur.com/mt79yaC.png)
166234
167235
## References
168236
237+
**Articles**
238+
169239
- [Asking for Required Annotations](https://medium.com/flow-type/asking-for-required-annotations-64d4f9c1edf8)
170-
- [Flow Typed tests for React Redux `connect`](https://github.com/flow-typed/flow-typed/blob/master/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connect.js#L449)
171-
- [Quick Note Fixing `connect` FlowType Annotation after 0.89](https://dev.to/wgao19/quick-note-fixing-connect-flowtype-annotation-after-089-joi)
172-
- [Connect Examples from Flow Typed tests](https://github.com/flow-typed/flow-typed/blob/master/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connect.js#L156)
240+
241+
**Upgrading guides**
242+
173243
- [Ville's and Jordan Brown's guide: _Adding Type Parameters to Connect_](https://gist.github.com/jbrown215/f425203ef30fdc8a28c213b90ba7a794)
244+
- [Quick Note Fixing `connect` FlowType Annotation after 0.89](https://dev.to/wgao19/quick-note-fixing-connect-flowtype-annotation-after-089-joi)
245+
246+
**Talks**
247+
248+
- [Flow Be Happy](https://engineers.sg/video/flow-be-happy-reactjs-singapore--3419) A talk on upgrading Flow past 0.85, [slides](https://flow-be-happy.netlify.com/)
249+
250+
**Others**
251+
252+
- [Flow Typed tests for React Redux `connect`](https://github.com/flow-typed/flow-typed/blob/master/definitions/npm/react-redux_v5.x.x/flow_v0.89.x-/test_connect.js)
174253
- [flow-typed/#2946: Discussion after 0.85](https://github.com/flow-typed/flow-typed/issues/2946)
175254
- Add support for Flow 0.89+: [#3012](https://github.com/flow-typed/flow-typed/pull/3035), [#3035](https://github.com/flow-typed/flow-typed/pull/3035)
176255
- [What's `_`?](https://github.com/facebook/flow/commit/ec70da4510d3a092fa933081c083bd0e513d0518)
177-
- [Flow Be Happy](https://engineers.sg/video/flow-be-happy-reactjs-singapore--3419) A talk on migrating Flow past 0.85

0 commit comments

Comments
 (0)