Skip to content

Commit 04dd3b6

Browse files
authored
chore(docs): reversion docs for cell, type fixes (#8236)
1 parent c17cce9 commit 04dd3b6

3 files changed

Lines changed: 457 additions & 91 deletions

File tree

docs/versioned_docs/version-5.0/cells.md

Lines changed: 43 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -21,69 +21,56 @@ yarn rw generate cell <name>
2121

2222
This creates a directory named `<name>Cell` in `web/src/components` with four files:
2323

24-
```bash
25-
~/redwood-app$ yarn rw generate cell user
26-
yarn run v1.22.4
27-
$ /redwood-app/node_modules/.bin/rw g cell user
28-
✔ Generating cell files...
29-
✔ Writing `./web/src/components/UserCell/UserCell.mock.js`...
30-
✔ Writing `./web/src/components/UserCell/UserCell.stories.js`...
31-
✔ Writing `./web/src/components/UserCell/UserCell.test.js`...
32-
✔ Writing `./web/src/components/UserCell/UserCell.js`...
33-
Done in 1.07s.
34-
```
24+
| File | Description |
25+
| :---------------------- | :------------------------------------------------------ |
26+
| `<name>Cell.js` | The actual Cell |
27+
| `<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 |
3530

3631
### Single Item Cell vs List Cell
3732

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.
3934
Redwood's Cell generator can do both.
4035

4136
First, it detects if `<name>` is singular or plural.
4237
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:
4439

45-
```
40+
```bash
4641
yarn rw generate cell equipment --list
4742
```
4843

4944
## Cells in-depth
5045

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

5548
## Usage
5649

5750
With Cells, you have a total of seven exports to work with:
5851

59-
| Name | Type | Description |
60-
| :------------ | :----------------- | :----------------------------------------------------------- |
61-
| `QUERY` | `string\|function` | The query to execute |
62-
| `beforeQuery` | `function` | Lifecycle hook; prepares variables and options for the query |
63-
| `isEmpty` | `function` | Lifecycle hook; decides if Cell should render Empty |
64-
| `afterQuery` | `function` | Lifecycle hook; sanitizes data returned from the query |
65-
| `Loading` | `component` | If the request is in flight, render this component |
66-
| `Empty` | `component` | If there's no data (`null` or `[]`), render this component |
67-
| `Failure` | `component` | If something went wrong, render this component |
68-
| `Success` | `component` | If the data has loaded, render this component |
52+
| Name | Type | Description |
53+
| :------------ | :---------------- | :----------------------------------------------------------- |
54+
| `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 |
6962

7063
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.
7164

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`.
7866

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

8469
### QUERY
8570

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

8875
```jsx {7-10}
8976
export const QUERY = gql`{
@@ -104,15 +91,11 @@ So in this case, both `posts` and `authors` would be available to `Success`:
10491

10592
```jsx
10693
export const Success = ({ posts, authors }) => {
107-
// render logic with posts and authors
94+
// ...
10895
}
10996
```
11097

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:
113-
114-
<!-- Source: https://community.redwoodjs.com/t/custom-github-jwt-auth-with-redwood-auth-advice-needed/610 -->
115-
But what about variables? Well, 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`:
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`:
11699

117100
```jsx {7}
118101
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
144127
145128
### beforeQuery
146129
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).
148131

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

151134
```jsx
152135
export const beforeQuery = (props) => {
@@ -159,7 +142,6 @@ export const beforeQuery = (props) => {
159142

160143
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))
161144

162-
<!-- Source: https://github.com/redwoodjs/redwood/issues/717 -->
163145
```jsx
164146
export const beforeQuery = (props) => {
165147
return { variables: props, fetchPolicy: 'no-cache', pollInterval: 2500 }
@@ -190,13 +172,14 @@ export const beforeQuery = ({ word }: { word: string }) => {
190172
191173
### isEmpty
192174
193-
`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.
194176
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:
196178
197179
```jsx
198-
export const isEmpty = (data, { isDataEmpty }) =>
199-
isDataEmpty(data) || data?.blog?.status === 'hidden'
180+
export const isEmpty = (data, { isDataEmpty }) => {
181+
return isDataEmpty(data) || data?.blog?.status === 'hidden'
182+
}
200183
```
201184
202185
### afterQuery
@@ -206,56 +189,30 @@ Use it to sanitize data returned from `QUERY` before it gets there.
206189
207190
By default, `afterQuery` just returns the data as it is:
208191
209-
```jsx
210-
export const afterQuery = (data) => ({...data})
211-
```
212-
213192
### Loading
214193
215194
If there's no cached data and the request is in flight, a Cell renders `Loading`.
216195
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-
219196
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".
220197
221198
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.
222199
223200
### Empty
224201
225202
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-
const isDataNull = (data: DataObject) => {
231-
return dataField(data) === null
232-
}
233-
234-
const isDataEmptyArray = (data: DataObject) => {
235-
const field = dataField(data)
236-
return Array.isArray(field) && field.length === 0
237-
}
238-
239-
const dataField = (data: DataObject) => {
240-
return data[Object.keys(data)[0]]
241-
}
242-
243-
const isEmpty = (data: DataObject) => {
244-
return isDataNull(data) || isDataEmptyArray(data)
245-
}
246-
```
203+
By no data, we mean if the response is 1) `null` or 2) an empty array (`[]`).
247204
248205
### Failure
249206
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`:
251208
252209
```jsx {6}
253210
const QUERY = gql`
254211
query {
255212
posts {
256213
id
257214
title
258-
nonsense
215+
unTypedField
259216
}
260217
}
261218
`
@@ -283,34 +240,31 @@ export const Failure = ({ error, errorCode }: CellFailureProps) => {
283240
284241
If everything went well, a Cell renders `Success`.
285242
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.
287244
288245
So, if you're querying for `posts` and `authors`, instead of doing:
289246
290247
```jsx
291248
export const Success = ({ data }) => {
292249
const { posts, authors } = data
293250

294-
// render logic with posts and authors
295-
...
251+
// ...
296252
}
297253
```
298254
299-
Redwood does:
255+
Redwood lets you do:
300256
301257
```jsx
302258
export const Success = ({ posts, authors }) => {
303-
// render logic with posts and authors
304-
...
259+
// ...
305260
}
306261
```
307262
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.
310264
311265
:::tip
312266
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.
314268
315269
:::
316270

0 commit comments

Comments
 (0)