You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
|`<name>Cell.test.js`| Jest tests for each state of the Cell |
28
+
|`<name>Cell.stories.js`| Storybook stories for each state of the Cell |
29
+
|`<name>Cell.mock.js`| Mock data for both the Jest tests and Storybook stories |
35
30
36
31
### Single Item Cell vs List Cell
37
32
38
-
Sometimes you want a Cell that renders a single item, like the example above, and other times you want a Cell that renders a list.
33
+
Sometimes you want a Cell that renders a single item and other times you want a Cell that renders a list.
39
34
Redwood's Cell generator can do both.
40
35
41
36
First, it detects if `<name>` is singular or plural.
42
37
For example, to generate a Cell that renders a list of users, run `yarn rw generate cell users`.
43
-
Second, for **irregular words** whose singular and plural are identical, such as *equipment* or *pokemon*, you can specify the `--list` flag to tell Redwood to generate a list Cell explicitly:
38
+
Second, for irregular words whose singular and plural are the same, such as "equipment" or "pokemon", you can pass `--list` to tell Redwood to generate a list Cell explicitly:
44
39
45
-
```
40
+
```bash
46
41
yarn rw generate cell equipment --list
47
42
```
48
43
49
44
## Cells in-depth
50
45
51
-
We'll go over each of these files in detail. But know that the file appended with just `.js` (in the example above, `UserCell.js`) contains all your Cell's logic.
52
-
53
-
Off the bat, this file exports five constants: `QUERY`, `Loading` , `Empty` , `Failure` and `Success`. The root query in `QUERY` is the same as `<name>` so that, if you're generating a cell based on a model in your `schema.prisma`, you can get something out of the database right away. But there's a good chance you won't generate your Cell this way, so if you need to, make sure to change the root query. See the [Cells](tutorial/chapter2/cells.md#our-first-cell) section of the Tutorial for a great example of this.
46
+
Cells exports five constants: `QUERY`, `Loading` , `Empty` , `Failure` and `Success`. The root query in `QUERY` is the same as `<name>` so that, if you're generating a cell based on a model in your `schema.prisma`, you can get something out of the database right away. But there's a good chance you won't generate your Cell this way, so if you need to, make sure to change the root query. See the [Cells](tutorial/chapter2/cells.md#our-first-cell) section of the Tutorial for a great example of this.
54
47
55
48
## Usage
56
49
57
50
With Cells, you have a total of seven exports to work with:
|`QUERY`|`string,function`| The query to execute |
55
+
|`beforeQuery`|`function`| Lifecycle hook; prepares variables and options for the query |
56
+
|`isEmpty`|`function`| Lifecycle hook; decides if the Cell should render Empty |
57
+
|`afterQuery`|`function`| Lifecycle hook; sanitizes data returned from the query |
58
+
|`Loading`|`component`| If the request is in flight, render this component |
59
+
|`Empty`|`component`| If there's no data (`null` or `[]`), render this component |
60
+
|`Failure`|`component`| If something went wrong, render this component |
61
+
|`Success`|`component`| If the data has loaded, render this component |
69
62
70
63
Only `QUERY` and `Success` are required. If you don't export `Empty`, empty results are sent to `Success`, and if you don't export `Failure`, error is output to the console.
71
64
72
-
In addition to displaying the right component, Cells also make sure to funnel the right props to the right component. `Loading`, `Empty`, `Failure`, and `Success` all have access to the props passed down from the Cell in good ol' React fashion, and most of `useQuery`'s return (more on that below). In addition to all those props, `Empty` and `Success` also get the `data` returned from the query and an `updating` boolean prop saying whether the Cell is currently fetching new data or not. `Failure` also gets `updating` and exclusive access to `error` and `errorCode`.
73
-
74
-
With this many props coming in, there's a risk of name clashing. A couple things to look out for are:
75
-
76
-
- Your Cell has a prop with the same name as root-level data returned by your query.
77
-
- In this case, the root-level data overrides your prop. But since props double as query variables, you can destructure the `variables` prop that `useQuery` returns to retrieve it. Or you can just rename the prop on the Cell!
65
+
In addition to displaying the right component at the right time, Cells also funnel the right props to the right component. `Loading`, `Empty`, `Failure`, and `Success` all have access to the props passed down from the Cell in good ol' React fashion, and most of the `useQuery` hook's return as a prop called `queryResult`. In addition to all those props, `Empty` and `Success` also get the `data` returned from the query and an `updating` prop indicating whether the Cell is currently fetching new data. `Failure` also gets `updating` and exclusive access to `error` and `errorCode`.
78
66
79
-
- Your Cell has props or query results with the same name as any of `useQuery`'s returns.
80
-
- In this case, `useQuery`'s returns overwrite the props and results.
81
-
82
-
We mentioned above that Cells receive "most" of what's returned from `useQuery`. You can see exactly what `useQuery` returns in Apollo Client's [API reference](https://www.apollographql.com/docs/react/api/react/hooks/#result). Note that, as we just mentioned, `error` and `data` get some special treatment.
67
+
We mentioned above that Cells receive "most" of what's returned from the `useQuery` hook. You can see exactly what `useQuery` returns in Apollo Client's [API reference](https://www.apollographql.com/docs/react/api/react/hooks/#result). Again note that `error` and `data` get some special treatment.
83
68
84
69
### QUERY
85
70
86
-
`QUERY` can be a string or a function. Note that it's totally more than ok to have more than one root query. Here's an example of that:
71
+
`QUERY` can be a string or a function. If `QUERY` is a function, it has to return a valid GraphQL document.
72
+
73
+
It's more-than ok to have more than one root query. Here's an example:
87
74
88
75
```jsx {7-10}
89
76
exportconstQUERY=gql`{
@@ -104,15 +91,11 @@ So in this case, both `posts` and `authors` would be available to `Success`:
104
91
105
92
```jsx
106
93
export const Success = ({ posts, authors }) => {
107
-
// render logic with posts and authors
94
+
// ...
108
95
}
109
96
```
110
97
111
-
If `QUERY` is a function, it has to return a valid GraphQL document.
112
-
Use a function if your queries need to be more dynamic:
But what about variables? Well, Cells are setup to use any props they receive from their parent as variables (thingsaresetupthiswayin`beforeQuery`). For example, here `BlogPostCell` takes a prop, `numberToShow`, so `numberToShow` is just available to your `QUERY`:
98
+
Normally queries have variables. Cells are setup to use any props they receive from their parent as variables (things are setup this way in`beforeQuery`). For example, here `BlogPostCell` takes a prop, `numberToShow`, so `numberToShow` is just available to your `QUERY`:
116
99
117
100
```jsx {7}
118
101
import BlogPostsCell from 'src/components/BlogPostsCell'
@@ -144,9 +127,9 @@ This means you can think backwards about your Cell's props from your SDL: whatev
144
127
145
128
### beforeQuery
146
129
147
-
`beforeQuery` is a lifecycle hook. The best way to think about it is as an API for configuring Apollo Client's `Query` component (so you might want to check out Apollo's [docs](https://www.apollographql.com/docs/react/api/react-components/#query) for it).
130
+
`beforeQuery` is a lifecycle hook. The best way to think about it is as a chance to configure [Apollo Client's `useQuery` hook](https://www.apollographql.com/docs/react/api/react/hooks#options).
148
131
149
-
By default, `beforeQuery` gives any props passed from the parent component to `Query` so that they're available as variables for `QUERY`. It'll also set the fetch policy to `'cache-and-network'` since we felt it matched the behavior users want most of the time.
132
+
By default, `beforeQuery` gives any props passed from the parent component to `QUERY` so that they're available as variables for it. It'll also set the fetch policy to `'cache-and-network'` since we felt it matched the behavior users want most of the time:
For example, if you wanted to turn on Apollo's polling option, and prevent caching, you could export something like this (see Apollo's docs on [polling](https://www.apollographql.com/docs/react/data/queries/#polling) and [caching](https://www.apollographql.com/docs/react/data/queries/#setting-a-fetch-policy))
`isEmpty` is an optional lifecycle hook. It returns a boolean to indicate if Cell is empty. Use it to override the [default check](#empty).
175
+
`isEmpty` is an optional lifecycle hook. It returns a boolean to indicate if the Cell should render empty. Use it to override the default check, which checks if the Cell's root fields are null or empty arrays.
194
176
195
-
It receives the `data`, and the default check reference `isDataEmpty`, so it's possible to extend the default check with custom logic.
177
+
It receives two parameters: 1) the `data`, and 2) an object that has the default `isEmpty` function, named `isDataEmpty`, so that you can extend the default:
@@ -206,56 +189,30 @@ Use it to sanitize data returned from `QUERY` before it gets there.
206
189
207
190
By default, `afterQuery` just returns the data as it is:
208
191
209
-
```jsx
210
-
exportconstafterQuery= (data) => ({...data})
211
-
```
212
-
213
192
### Loading
214
193
215
194
If there's no cached data and the request is in flight, a Cell renders `Loading`.
216
195
217
-
<!-- For a production example, navigate to [predictcovid.com](https://predictcovid.com), the first site made with Redwood. Usually, when you first navigate there, you'll see most of the dashboard spinning. Those are `Loading` components in action! -->
218
-
219
196
When you're developing locally, you can catch your Cell waiting to hear back for a moment if set your speed in the Inspector's **Network** tab to something like "Slow 3G".
220
197
221
198
But why bother with Slow 3G when Redwood comes with Storybook? Storybook makes developing components like `Loading` (and `Failure`) a breeze. We don't have to put up with hacky workarounds like Slow 3G or intentionally breaking our app just to develop our components.
222
199
223
200
### Empty
224
201
225
202
A Cell renders this component if there's no data.
226
-
227
-
What do we mean by no data? We mean if the response is 1) `null` or 2) an empty array (`[]`). There's actually four functions in [createCell.tsx](https://github.com/redwoodjs/redwood/blob/main/packages/web/src/components/createCell.tsx) dedicated just to figuring this out:
228
-
229
-
```jsx title="createCell.tsx"
230
-
constisDataNull= (data:DataObject) => {
231
-
returndataField(data) ===null
232
-
}
233
-
234
-
constisDataEmptyArray= (data:DataObject) => {
235
-
constfield=dataField(data)
236
-
returnArray.isArray(field) &&field.length===0
237
-
}
238
-
239
-
constdataField= (data:DataObject) => {
240
-
return data[Object.keys(data)[0]]
241
-
}
242
-
243
-
constisEmpty= (data:DataObject) => {
244
-
returnisDataNull(data) ||isDataEmptyArray(data)
245
-
}
246
-
```
203
+
By no data, we mean if the response is 1) `null` or 2) an empty array (`[]`).
247
204
248
205
### Failure
249
206
250
-
A Cell renders this component if something went wrong. You can quickly see this in action (it's easy to break things) if you add a nonsense field to your `QUERY`:
207
+
A Cell renders this component if something went wrong. You can quickly see this in action if you add an untyped field to your `QUERY`:
If everything went well, a Cell renders `Success`.
285
242
286
-
As mentioned, Success gets exclusive access to the `data` prop. But if you try to destructure it from props, you'll notice that it doesn't exist. This is because Redwood adds another layer of convenience: in [createCell.tsx](https://github.com/redwoodjs/redwood/blob/main/packages/web/src/components/createCell.tsx#L149), Redwood spreads `data` (using the spread operator, `...`) into `Success` so that you can just destructure whatever data you were expecting from your `QUERY` directly.
243
+
As mentioned, Success gets exclusive access to the `data` prop. But if you try to destructure it from `props`, you'll notice that it doesn't exist. This is because Redwood adds a layer of convenience: Redwood spreads `data` into `Success` so that you can just destructure whatever data you were expecting from your `QUERY` directly.
287
244
288
245
So, if you're querying for `posts` and `authors`, instead of doing:
289
246
290
247
```jsx
291
248
exportconstSuccess= ({ data }) => {
292
249
const { posts, authors } = data
293
250
294
-
// render logic with posts and authors
295
-
...
251
+
// ...
296
252
}
297
253
```
298
254
299
-
Redwood does:
255
+
Redwood lets you do:
300
256
301
257
```jsx
302
258
exportconstSuccess= ({ posts, authors }) => {
303
-
// render logic with posts and authors
304
-
...
259
+
// ...
305
260
}
306
261
```
307
262
308
-
Note that you can still pass any other props to `Success`. After all, it's still just a React component.
309
-
263
+
Note that you can still pass any other props to `Success`. After all, it's just a React component.
310
264
311
265
:::tip
312
266
313
-
Looking for info on how TypeScript works with Cells? Check out the [Utility Types](typescript/utility-types.md#cell) doc
267
+
Looking for info on how TypeScript works with Cells? Check out the [Utility Types](typescript/utility-types.md#cells) doc.
0 commit comments