Skip to content

Commit f1d9dab

Browse files
committed
use DataTable in Tutorial instead of Datagrid
1 parent 6479209 commit f1d9dab

File tree

1 file changed

+124
-107
lines changed

1 file changed

+124
-107
lines changed

docs/Tutorial.md

Lines changed: 124 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ The final result is a web application that allows you to list, create, edit, and
2626
React-admin is built on React. To start, we'll use [create-react-admin](./CreateReactAdmin.md) to bootstrap a new web application:
2727

2828
```sh
29-
npm create react-admin@latest test-admin
29+
npm create react-admin@latest test-admin -- --interactive
3030
# or
31-
yarn create react-admin@latest test-admin
31+
yarn create react-admin test-admin --interactive
3232
```
3333

3434
When prompted, choose **JSON Server** as the data provider, then **None** as the auth provider. Do not add any resources for now and press **Enter**. Next, choose either `npm` or `yarn` and press **Enter**. Once everything is installed, run the following commands:
@@ -168,20 +168,20 @@ Copy this code and create a new `UserList` component in a new file called `users
168168

169169
```tsx
170170
// in src/users.tsx
171-
import { List, Datagrid, TextField, EmailField } from "react-admin";
171+
import { List, DataTable, EmailField } from "react-admin";
172172

173173
export const UserList = () => (
174174
<List>
175-
<Datagrid>
176-
<TextField source="id" />
177-
<TextField source="name" />
178-
<TextField source="username" />
179-
<EmailField source="email" />
180-
<TextField source="address.street" />
181-
<TextField source="phone" />
182-
<TextField source="website" />
183-
<TextField source="company.name" />
184-
</Datagrid>
175+
<DataTable>
176+
<DataTable.Col source="id" />
177+
<DataTable.Col source="name" />
178+
<DataTable.Col source="username" />
179+
<DataTable.Col source="email" field={EmailField} />
180+
<DataTable.Col source="address.street" />
181+
<DataTable.Col source="phone" />
182+
<DataTable.Col source="website" />
183+
<DataTable.Col source="company.name" />
184+
</DataTable>
185185
</List>
186186
);
187187
```
@@ -214,16 +214,16 @@ Let's take a closer look at the `<UserList>` component:
214214
```tsx
215215
export const UserList = () => (
216216
<List>
217-
<Datagrid>
218-
<TextField source="id" />
219-
<TextField source="name" />
220-
<TextField source="username" />
221-
<EmailField source="email" />
222-
<TextField source="address.street" />
223-
<TextField source="phone" />
224-
<TextField source="website" />
225-
<TextField source="company.name" />
226-
</Datagrid>
217+
<DataTable>
218+
<DataTable.Col source="id" />
219+
<DataTable.Col source="name" />
220+
<DataTable.Col source="username" />
221+
<DataTable.Col source="email" field={EmailField} />
222+
<DataTable.Col source="address.street" />
223+
<DataTable.Col source="phone" />
224+
<DataTable.Col source="website" />
225+
<DataTable.Col source="company.name" />
226+
</DataTable>
227227
</List>
228228
);
229229
```
@@ -238,7 +238,7 @@ The root component, [`<List>`](./List.md), reads the query parameters, fetches d
238238

239239
This demonstrates the goal of react-admin: helping developers build sophisticated applications with simple syntax.
240240

241-
In most frameworks, "simple" often implies limited capabilities, making it challenging to extend beyond basic features. React-admin addresses this through *composition*. `<List>` handles data fetching, while rendering is delegated to its child—in this case, [`<Datagrid>`](./Datagrid.md). Essentially, the code composes the functionalities of `<List>` and `<Datagrid>` functionalities.
241+
In most frameworks, "simple" often implies limited capabilities, making it challenging to extend beyond basic features. React-admin addresses this through *composition*. `<List>` handles data fetching, while rendering is delegated to its child—in this case, [`<DataTable>`](./DataTable.md). Essentially, the code composes the functionalities of `<List>` and `<DataTable>` functionalities.
242242

243243
This means we can compose `<List>` with another component - for instance [`<SimpleList>`](./SimpleList.md):
244244

@@ -275,12 +275,12 @@ React-admin's layout is responsive by default. Try resizing your browser, and yo
275275
Your browser does not support the video tag.
276276
</video>
277277

278-
However, `<SimpleList>` has low information density on desktop. Let's modify `<UserList>` to use `<Datagrid>` on larger screens and `<SimpleList>` on smaller screens. We can achieve this using [Material UI's `useMediaQuery` hook](https://mui.com/material-ui/react-use-media-query/):
278+
However, `<SimpleList>` has low information density on desktop. Let's modify `<UserList>` to use `<DataTable>` on larger screens and `<SimpleList>` on smaller screens. We can achieve this using [Material UI's `useMediaQuery` hook](https://mui.com/material-ui/react-use-media-query/):
279279

280280
```tsx
281281
// in src/users.tsx
282282
import { useMediaQuery, Theme } from "@mui/material";
283-
import { List, SimpleList, Datagrid, TextField, EmailField } from "react-admin";
283+
import { List, SimpleList, DataTable, EmailField } from "react-admin";
284284

285285
export const UserList = () => {
286286
const isSmall = useMediaQuery<Theme>((theme) => theme.breakpoints.down("sm"));
@@ -293,16 +293,16 @@ export const UserList = () => {
293293
tertiaryText={(record) => record.email}
294294
/>
295295
) : (
296-
<Datagrid>
297-
<TextField source="id" />
298-
<TextField source="name" />
299-
<TextField source="username" />
300-
<EmailField source="email" />
301-
<TextField source="address.street" />
302-
<TextField source="phone" />
303-
<TextField source="website" />
304-
<TextField source="company.name" />
305-
</Datagrid>
296+
<DataTable>
297+
<DataTable.Col source="id" />
298+
<DataTable.Col source="name" />
299+
<DataTable.Col source="username" />
300+
<DataTable.Col source="email" field={EmailField} />
301+
<DataTable.Col source="address.street" />
302+
<DataTable.Col source="phone" />
303+
<DataTable.Col source="website" />
304+
<DataTable.Col source="company.name" />
305+
</DataTable>
306306
)}
307307
</List>
308308
);
@@ -321,22 +321,25 @@ The `<List>` component's child can be anything—even a custom component with it
321321

322322
## Selecting Columns
323323

324-
Let's get back to `<Datagrid>`. It reads the data fetched by `<List>`, then renders a table with one row for each record. `<Datagrid>` uses its child components (here, a list of [Field component](./Fields.md)) to render the columns. Each Field component renders one field of the current record, specified by the `source` prop.
324+
Let's get back to `<DataTable>`.
325+
It reads the data fetched by `<List>`, then renders a table with one row for each record. `<DataTable>` uses its child components (here, a list of [Field component](./Fields.md)) to render the columns.
326+
Each `<DataTable.Col>` component renders one field of the current record, specified by the `source` prop.
325327

326-
`<ListGuesser>` created one column for every field in the API response. That's a bit too much for a usable grid, so let's remove a couple of `<TextField>` components from the Datagrid and see the effect:
328+
`<ListGuesser>` created one column for every field in the API response.
329+
That's a bit too much for a usable grid, so let's remove a couple of `<DataTable.Col>` components from the DataTable and see the effect:
327330

328331
```diff
329332
// in src/users.tsx
330-
<Datagrid>
331-
<TextField source="id" />
332-
<TextField source="name" />
333-
- <TextField source="username" />
334-
<EmailField source="email" />
335-
- <TextField source="address.street" />
336-
<TextField source="phone" />
337-
<TextField source="website" />
338-
<TextField source="company.name" />
339-
</Datagrid>
333+
<DataTable>
334+
<DataTable.Col source="id" />
335+
<DataTable.Col source="name" />
336+
- <DataTable.Col source="username" />
337+
<DataTable.Col source="email" field={EmailField} />
338+
- <DataTable.Col source="address.street" />
339+
<DataTable.Col source="phone" />
340+
<DataTable.Col source="website" />
341+
<DataTable.Col source="company.name" />
342+
</DataTable>
340343
```
341344

342345
[![Users List](./img/tutorial_users_list_selected_columns.png)](./img/tutorial_users_list_selected_columns.png)
@@ -345,24 +348,25 @@ In react-admin, most configuration is done through components. Instead of using
345348

346349
## Using Field Types
347350

348-
So far, you've used [`<TextField>`](./TextField.md) and [`<EmailField>`](./EmailField.md). React-admin provides [many more Field components](./Fields.md) to handle different data types—numbers, dates, images, arrays, and more.
351+
So far, you've used simples [`<DataTable.Col>`](.//DataTable.md#datatablecol) and [`EmailField`](./EmailField.md) as [a `DataTable.Col` `field`](./DataTable.md#field).
352+
React-admin provides [many more Field components](./Fields.md) to handle different data types—numbers, dates, images, arrays, and more.
349353

350354
For instance, instead of displaying the `website` field as plain text, you could make it a clickable link using [`<UrlField>`](./UrlField.md):
351355

352356
```diff
353357
// in src/users.tsx
354-
-import { List, SimpleList, Datagrid, TextField, EmailField } from "react-admin";
355-
+import { List, SimpleList, Datagrid, TextField, EmailField, UrlField } from "react-admin";
358+
-import { List, SimpleList, DataTable, EmailField } from "react-admin";
359+
+import { List, SimpleList, DataTable, EmailField, UrlField } from "react-admin";
356360
// ...
357-
<Datagrid>
358-
<TextField source="id" />
359-
<TextField source="name" />
360-
<EmailField source="email" />
361-
<TextField source="phone" />
362-
- <TextField source="website" />
363-
+ <UrlField source="website" />
364-
<TextField source="company.name" />
365-
</Datagrid>
361+
<DataTable>
362+
<DataTable.Col source="id" />
363+
<DataTable.Col source="name" />
364+
<DataTable.Col source="email" field={EmailField} />
365+
<DataTable.Col source="phone" />
366+
- <DataTable.Col source="website" />
367+
+ <DataTable.Col source="website" field={UrlField} />
368+
<DataTable.Col source="company.name" />
369+
</DataTable>
366370
```
367371

368372
[![Url Field](./img/tutorial_url_field.png)](./img/tutorial_url_field.png)
@@ -371,9 +375,11 @@ This is typical of the early stages of development with react-admin: use a guess
371375

372376
## Writing A Custom Field
373377

374-
In react-admin, fields are just React components. When rendered, they grab the `record` fetched from the API (e.g. `{ "id": 2, "name": "Ervin Howell", "website": "anastasia.net", ... }`) using a custom hook, and use the `source` prop (e.g. `website`) to get the value they should display (e.g. "anastasia.net").
378+
In react-admin, fields are just React components.
379+
When rendered, they grab the `record` fetched from the API (e.g. `{ "id": 2, "name": "Ervin Howell", "website": "anastasia.net", ... }`) using a custom hook, and use the `source` prop (e.g. `website`) to get the value they should display (e.g. "anastasia.net").
375380

376-
That means you can do the same to [write a custom field](./Fields.md#writing-your-own-field-component). For instance, here is a simplified version of the `<UrlField>`:
381+
That means you can do the same to [write a custom field](./Fields.md#writing-your-own-field-component).
382+
For instance, here is a simplified version of the `<UrlField>`:
377383

378384
```tsx
379385
// in src/MyUrlField.tsx
@@ -388,25 +394,27 @@ const MyUrlField = ({ source }: { source: string }) => {
388394
export default MyUrlField;
389395
```
390396

391-
For each row, `<Datagrid>` creates a `RecordContext` and stores the current record in it. [`useRecordContext`](./useRecordContext.md) allows you to read that record. It's one of the 50+ headless hooks that react-admin exposes to let you build your own components without forcing a particular UI.
397+
For each row, `<DataTable>` creates a `RecordContext` and stores the current record in it.
398+
[`useRecordContext`](./useRecordContext.md) allows you to read that record.
399+
It's one of the 50+ headless hooks that react-admin exposes to let you build your own components without forcing a particular UI.
392400

393401
You can use the `<MyUrlField>` component in `<UserList>` instead of react-admin's `<UrlField>` component, and it will work just the same.
394402

395403
```diff
396404
// in src/users.tsx
397-
-import { List, SimpleList, Datagrid, TextField, EmailField, UrlField } from "react-admin";
398-
+import { List, SimpleList, Datagrid, TextField, EmailField } from "react-admin";
405+
-import { List, SimpleList, DataTable, EmailField, UrlField } from "react-admin";
406+
+import { List, SimpleList, DataTable, EmailField } from "react-admin";
399407
+import MyUrlField from './MyUrlField';
400408
// ...
401-
<Datagrid>
402-
<TextField source="id" />
403-
<TextField source="name" />
404-
<EmailField source="email" />
405-
<TextField source="phone" />
406-
- <UrlField source="website" />
407-
+ <MyUrlField source="website" />
408-
<TextField source="company.name" />
409-
</Datagrid>
409+
<DataTable>
410+
<DataTable.Col source="id" />
411+
<DataTable.Col source="name" />
412+
<DataTable.Col source="email" source={EmailField} />
413+
<DataTable.Col source="phone" />
414+
- <DataTable.Col source="website" source={UrlField} />
415+
+ <DataTable.Col source="website" source={MyUrlField} />
416+
<DataTable.Col source="company.name" />
417+
</DataTable>
410418
```
411419

412420
This means react-admin never blocks you: if one react-admin component doesn't perfectly suit your needs, you can just swap it with your own version.
@@ -478,20 +486,23 @@ export const App = () => (
478486

479487
[![Guessed Post List](./img/tutorial_guessed_post_list.png)](./img/tutorial_guessed_post_list.png)
480488

481-
The `ListGuesser` suggests using a [`<ReferenceField>`](./ReferenceField.md) for the `userId` field. Let's play with this new field by creating the `PostList` component based on the code dumped by the guesser:
489+
The `ListGuesser` suggests using a [`<ReferenceField>`](./ReferenceField.md) for the `userId` field.
490+
Let's play with this new field by creating the `PostList` component based on the code dumped by the guesser:
482491

483492
```tsx
484493
// in src/posts.tsx
485-
import { List, Datagrid, TextField, ReferenceField } from "react-admin";
494+
import { List, DataTable, ReferenceField } from "react-admin";
486495

487496
export const PostList = () => (
488497
<List>
489-
<Datagrid>
490-
<ReferenceField source="userId" reference="users" />
491-
<TextField source="id" />
492-
<TextField source="title" />
493-
<TextField source="body" />
494-
</Datagrid>
498+
<DataTable>
499+
<DataTable.Col source="userId">
500+
<ReferenceField source="userId" reference="users" />
501+
</DataTable.Col>
502+
<DataTable.Col source="id" />
503+
<DataTable.Col source="title" />
504+
<DataTable.Col source="body" />
505+
</DataTable>
495506
</List>
496507
);
497508
```
@@ -521,26 +532,32 @@ When displaying the posts list, react-admin is smart enough to display the `name
521532

522533
The `<ReferenceField>` component fetches the reference data, creates a `RecordContext` with the result, and renders the record representation (or its children).
523534

524-
**Tip**: Look at the network tab of your browser again: react-admin deduplicates requests for users and aggregates them in order to make only *one* HTTP request to the `/users` endpoint for the whole Datagrid. That's one of many optimizations that keep the UI fast and responsive.
535+
**Tip**: Look at the network tab of your browser again: react-admin deduplicates requests for users and aggregates them in order to make only *one* HTTP request to the `/users` endpoint for the whole DataTable. That's one of many optimizations that keep the UI fast and responsive.
525536

526-
To finish the post list, place the post `id` field as the first column, and remove the `body` field. From a UX point of view, fields containing large chunks of text should not appear in a Datagrid, only in detail views. Also, to make the Edit action stand out, let's replace the default `rowClick` action with an explicit action button:
537+
To finish the post list, place the post `id` field as the first column, and remove the `body` field.
538+
From a UX point of view, fields containing large chunks of text should not appear in a DataTable, only in detail views.
539+
Also, to make the Edit action stand out, let's replace the default `rowClick` action with an explicit action button:
527540

528541
```diff
529542
// in src/posts.tsx
530-
-import { List, Datagrid, TextField, ReferenceField } from "react-admin";
531-
+import { List, Datagrid, TextField, ReferenceField, EditButton } from "react-admin";
543+
-import { List, DataTable, ReferenceField } from "react-admin";
544+
+import { List, DataTable, ReferenceField, EditButton } from "react-admin";
532545

533546
export const PostList = () => (
534547
<List>
535-
- <Datagrid>
536-
+ <Datagrid rowClick={false}>
537-
+ <TextField source="id" />
538-
<ReferenceField source="userId" reference="users" />
539-
- <TextField source="id" />
540-
<TextField source="title" />
541-
- <TextField source="body" />
542-
+ <EditButton />
543-
</Datagrid>
548+
- <DataTable>
549+
+ <DataTable rowClick={false}>
550+
+ <DataTable.Col source="id" />
551+
<DataTable.Col source="userId">
552+
<ReferenceField source="userId" reference="users" />
553+
</DataTable.Col source="userId">
554+
- <DataTable.Col source="id" />
555+
<DataTable.Col source="title" />
556+
- <DataTable.Col source="body" />
557+
+ <DataTable.Col>
558+
+ <EditButton />
559+
+ </DataTable.Col>
560+
</DataTable>
544561
</List>
545562
);
546563
```
@@ -583,13 +600,15 @@ Now that the `users` resource has a `show` view, you can also link to it from th
583600
// in src/posts.tsx
584601
export const PostList = () => (
585602
<List>
586-
<Datagrid>
587-
- <ReferenceField source="userId" reference="users" />
588-
+ <ReferenceField source="userId" reference="users" link="show" />
589-
<TextField source="id" />
590-
<TextField source="title" />
591-
<TextField source="body" />
592-
</Datagrid>
603+
<DataTable>
604+
<DataTable.Col>
605+
- <ReferenceField source="userId" reference="users" />
606+
+ <ReferenceField source="userId" reference="users" link="show" />
607+
</DataTable.Col>
608+
<DataTable.Col source="id" />
609+
<DataTable.Col source="title" />
610+
<DataTable.Col source="body" />
611+
</DataTable>
593612
</List>
594613
);
595614
```
@@ -633,8 +652,7 @@ Copy the `<PostEdit>` code dumped by the guesser in the console to the `posts.ts
633652
// in src/posts.tsx
634653
import {
635654
List,
636-
Datagrid,
637-
TextField,
655+
DataTable,
638656
ReferenceField,
639657
EditButton,
640658
Edit,
@@ -699,7 +717,7 @@ export const PostEdit = () => (
699717
```
700718
{% endraw %}
701719

702-
If you've understood the `<List>` component, the `<Edit>` component will be no surprise. It's responsible for fetching the record and displaying the page title. It passes the record down to the [`<SimpleForm>`](./SimpleForm.md) component, which is responsible for the form layout, default values, and validation. Just like `<Datagrid>`, `<SimpleForm>` uses its children to determine the form inputs to display. It expects [*input components*](./Inputs.md) as children. [`<TextInput>`](./TextInput.md) and [`<ReferenceInput>`](./ReferenceInput.md) are such inputs.
720+
If you've understood the `<List>` component, the `<Edit>` component will be no surprise. It's responsible for fetching the record and displaying the page title. It passes the record down to the [`<SimpleForm>`](./SimpleForm.md) component, which is responsible for the form layout, default values, and validation. Just like `<DataTable>`, `<SimpleForm>` uses its children to determine the form inputs to display. It expects [*input components*](./Inputs.md) as children. [`<TextInput>`](./TextInput.md) and [`<ReferenceInput>`](./ReferenceInput.md) are such inputs.
703721

704722
The `<ReferenceInput>` takes the same props as the `<ReferenceField>` (used earlier in the `<PostList>` page). `<ReferenceInput>` uses these props to fetch the API for possible references related to the current record (in this case, possible `users` for the current `post`). It then creates a context with the possible choices and renders an [`<AutocompleteInput>`](./AutocompleteInput.md), which is responsible for displaying the choices and letting the user select one.
705723

@@ -711,8 +729,7 @@ Let's allow users to create posts, too. Copy the `<PostEdit>` component into a `
711729
// in src/posts.tsx
712730
import {
713731
List,
714-
Datagrid,
715-
TextField,
732+
DataTable,
716733
ReferenceField,
717734
EditButton,
718735
Edit,

0 commit comments

Comments
 (0)