|
| 1 | +--- |
| 2 | +layout: default |
| 3 | +title: "RecordsIterator" |
| 4 | +storybook_path: ra-core-controller-list-recordsiterator |
| 5 | +--- |
| 6 | + |
| 7 | +# `<RecordsIterator>` |
| 8 | + |
| 9 | +Use the `<RecordsIterator>` component to render a list of records in a custom way. Pass a `render` function to customize how each record is displayed. Pass a `data` prop to use it out of a list context. |
| 10 | + |
| 11 | +## Usage |
| 12 | + |
| 13 | +Use `<RecordsIterator>` inside a [`ListContext`](./useListContext.md) to render each record: |
| 14 | + |
| 15 | +{% raw %} |
| 16 | +```jsx |
| 17 | +import { ListBase, RecordsIterator } from 'react-admin'; |
| 18 | + |
| 19 | +const MostVisitedPosts = () => ( |
| 20 | + <ListBase |
| 21 | + resource="posts" |
| 22 | + sort={{ field: 'views', order: 'DESC' }} |
| 23 | + perPage={20} |
| 24 | + > |
| 25 | + <ul> |
| 26 | + <RecordsIterator |
| 27 | + render={record => <li>{record.title} - {record.views}</li>} |
| 28 | + /> |
| 29 | + </ul> |
| 30 | + </ListBase> |
| 31 | +); |
| 32 | +``` |
| 33 | +{% endraw %} |
| 34 | + |
| 35 | +You can use `<RecordsIterator>` as a child of any component that provides a [`ListContext`](./useListContext.md), such as: |
| 36 | + |
| 37 | +- [`<List>`](./List.md), |
| 38 | +- [`<ListGuesser>`](./ListGuesser.md), |
| 39 | +- [`<ListBase>`](./ListBase.md), |
| 40 | +- [`<ReferenceArrayField>`](./ReferenceArrayField.md), |
| 41 | +- [`<ReferenceManyField>`](./ReferenceManyField.md) |
| 42 | + |
| 43 | +`<RecordsIterator>` expects that data is properly loaded, without error. If you want to handle loading, error, offline and empty states, use properties on the component providing you the list context (like [`<List>`](./List.md), [`<ReferenceArrayField>`](./ReferenceArrayField.md), [`<ReferenceManyField>`](./ReferenceManyField.md)). You can also make use of [`<WithListContext>`](./WithListContext.md) [`loading`](./WithListContext.md#loading), [`errorElement`](./WithListContext.md#errorelement), [`offline`](./WithListContext.md#offline) and [`empty`](./WithListContext.md#empty) props. |
| 44 | + |
| 45 | +{% raw %} |
| 46 | +```jsx |
| 47 | +import { ListBase, RecordsIterator, WithListContext } from 'react-admin'; |
| 48 | + |
| 49 | +const MostVisitedPosts = () => ( |
| 50 | + <ListBase |
| 51 | + resource="posts" |
| 52 | + sort={{ field: 'views', order: 'DESC' }} |
| 53 | + perPage={20} |
| 54 | + > |
| 55 | + <WithListContext |
| 56 | + loading={<p>Loading...</p>} |
| 57 | + errorElement={<p>Something went wrong</p>} |
| 58 | + empty={<p>No posts found</p>} |
| 59 | + offline={<p>You are offline</p>} |
| 60 | + > |
| 61 | + <ul> |
| 62 | + <RecordsIterator |
| 63 | + render={record => <li>{record.title} - {record.views}</li>} |
| 64 | + /> |
| 65 | + </ul> |
| 66 | + </WithListContext> |
| 67 | + </ListBase> |
| 68 | +); |
| 69 | +``` |
| 70 | +{% endraw %} |
| 71 | + |
| 72 | +## Props |
| 73 | + |
| 74 | +`<RecordsIterator>` exposes the following important props: |
| 75 | + |
| 76 | +| Prop | Required | Type | Default | Description | |
| 77 | +| ----------- | -------- |-----------------------------------| ------- | ---------------------------------------------------------------------------------------------------- | |
| 78 | +| `children` | Optional | `ReactNode` | - | The content to render for each record | |
| 79 | +| `data` | Optional | `RaRecord[]` | - | The records. Defaults to the `data` from the [`ListContext`](./useListContext.md) | |
| 80 | +| `isPending` | Optional | `boolean` | - | A boolean indicating whether the data is pending. Defaults to the `isPending` from the [`ListContext`](./useListContext.md) | |
| 81 | +| `render` | Optional | `(record: RaRecord) => ReactNode` | - | A function that returns the content to render for each record | |
| 82 | +| `total` | Optional | `number` | - | The total number of records. Defaults to the `total` from the [`ListContext`](./useListContext.md) | |
| 83 | + |
| 84 | +Either `children` or `render` is required. |
| 85 | + |
| 86 | +## `children` |
| 87 | + |
| 88 | +If provided, `RecordsIterator` will render the `children` prop once for each record, inside a [`RecordContext`](./useRecordContext.md). |
| 89 | + |
| 90 | +{% raw %} |
| 91 | +```tsx |
| 92 | +import { RecordsIterator, useRecordContext } from 'react-admin'; |
| 93 | + |
| 94 | +const PostList = () => ( |
| 95 | + <ul> |
| 96 | + <RecordsIterator> |
| 97 | + <PostItem /> |
| 98 | + </RecordsIterator> |
| 99 | + </ul> |
| 100 | +); |
| 101 | + |
| 102 | +const PostItem = () => { |
| 103 | + const record = useRecordContext(); |
| 104 | + if (!record) return null; |
| 105 | + return <li>{record.title} - {record.views}</li>; |
| 106 | +}; |
| 107 | +``` |
| 108 | +{% endraw %} |
| 109 | + |
| 110 | +**Note**: You can't provide both the `children` and the `render` props. If both are provided, `<RecordsIterator>` will use the `render` prop. |
| 111 | + |
| 112 | +This is useful for advanced scenarios where you need direct access to the record data or want to implement custom layouts. |
| 113 | + |
| 114 | +## `data` |
| 115 | + |
| 116 | +Although `<RecordsIterator>` reads the data from the closest [`<ListContext>`](./useListContext.md), you may provide it yourself when no such context is available: |
| 117 | + |
| 118 | +{% raw %} |
| 119 | +```jsx |
| 120 | +import { RecordsIterator, TextField } from 'react-admin'; |
| 121 | +import { customerSegments } from './customerSegments.json'; |
| 122 | + |
| 123 | +const PostList = () => ( |
| 124 | + <ul> |
| 125 | + <RecordsIterator |
| 126 | + data={customerSegments} |
| 127 | + total={customerSegments.length} |
| 128 | + > |
| 129 | + <li> |
| 130 | + <TextField source="name" /> |
| 131 | + </li> |
| 132 | + </RecordsIterator> |
| 133 | + </ul> |
| 134 | +); |
| 135 | +``` |
| 136 | +{% endraw %} |
| 137 | + |
| 138 | +## `isPending` |
| 139 | + |
| 140 | +Although `<RecordsIterator>` reads the `isPending` from the closest [`<ListContext>`](./useListContext.md), you may provide it yourself when no such context is available. This is useful when dealing with data not coming from the `dataProvider`: |
| 141 | + |
| 142 | +{% raw %} |
| 143 | +```tsx |
| 144 | +import { RecordsIterator } from 'react-admin'; |
| 145 | +import { useQuery } from '@tanstack/react-query'; |
| 146 | +import { fetchPostAnalytics } from './fetchPostAnalytics'; |
| 147 | + |
| 148 | +const DashboardMostVisitedPosts = () => { |
| 149 | + const { data, isPending } = useQuery({ |
| 150 | + queryKey: ['dashboard', 'posts'], |
| 151 | + queryFn: fetchPostAnalytics |
| 152 | + }); |
| 153 | + |
| 154 | + return ( |
| 155 | + <ul> |
| 156 | + <RecordsIterator |
| 157 | + data={data} |
| 158 | + isPending={isPending} |
| 159 | + render={record => <li>{record.title} - {record.views}</li>} |
| 160 | + /> |
| 161 | + </ul> |
| 162 | + ); |
| 163 | +} |
| 164 | +``` |
| 165 | +{% endraw %} |
| 166 | + |
| 167 | +## `render` |
| 168 | + |
| 169 | +If provided, `RecordsIterator` will call the `render` prop for each record. This is useful when the components you render need the record data to render themselves, or when you want to pass additional props to the rendered component. |
| 170 | + |
| 171 | +{% raw %} |
| 172 | +```tsx |
| 173 | +import { ListBase, RecordsIterator } from 'react-admin'; |
| 174 | + |
| 175 | +const PostList = () => ( |
| 176 | + <ListBase resource="posts"> |
| 177 | + <ul> |
| 178 | + <RecordsIterator |
| 179 | + render={record => <li>{record.title} - {record.views}</li>} |
| 180 | + /> |
| 181 | + </ul> |
| 182 | + </ListBase> |
| 183 | +); |
| 184 | +``` |
| 185 | +{% endraw %} |
| 186 | + |
| 187 | +**Note**: You can't provide both the `children` and the `render` props. If both are provided, `<RecordsIterator>` will use the `render` prop. |
| 188 | + |
| 189 | +## `total` |
| 190 | + |
| 191 | +Although `<RecordsIterator>` reads the total from the closest [`<ListContext>`](./useListContext), you may provide it yourself when no such context is available: |
| 192 | + |
| 193 | +{% raw %} |
| 194 | +```jsx |
| 195 | +import { RecordsIterator, TextField } from 'react-admin'; |
| 196 | +import { customerSegments } from './customerSegments.json'; |
| 197 | + |
| 198 | +const PostList = () => ( |
| 199 | + <ul> |
| 200 | + <RecordsIterator |
| 201 | + data={customerSegments} |
| 202 | + total={customerSegments.length} |
| 203 | + > |
| 204 | + <li> |
| 205 | + <TextField source="name" /> |
| 206 | + </li> |
| 207 | + </RecordsIterator> |
| 208 | + </ul> |
| 209 | +); |
| 210 | +``` |
| 211 | +{% endraw %} |
0 commit comments