Skip to content

Commit

Permalink
Merge pull request #3640 from marmelab/migrate-ExportButton
Browse files Browse the repository at this point in the history
[RFR] [BC Break] Migrate export button
  • Loading branch information
djhi authored Sep 3, 2019
2 parents 48ce290 + 8cf3aca commit 9b08ceb
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 166 deletions.
51 changes: 51 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -906,3 +906,54 @@ There are two breaking changes in the new `<AutocompleteInput>`:
- highlightFirstSuggestion={true}
/>
```

## The `exporter` function has changed signature

In a `List`, you can pass a custom `exporter` function to control the data downloaded by users when they cllick on the "Export" button.

```jsx
const CommentList = props => (
<List {...props} exporter={exportComments}>
// ...
</List>
)
```

In react-admin v3, you can still pass an `exporter` function this way, but its signature has changed:

```diff
-const exportComments = (data, fetchRelaterRecords, dispatch) => {
+const exportComments = (data, fetchRelaterRecords, dataProvider) => {
// ...
}
```

If you used `dispatch` to call the dataProvider using an action creator with a `callback` side effect, you will see that the v3 version makes your exporter code much simpler. If you used it to dispatch custom side effects (like notification or redirect), we recommend that you override the `<ExportButton>` component completely - it'll be much easier to maintain.

As a base, here is the simplified `ExportButton` code:

```jsx
import {
downloadCSV,
useDataProvider,
useNotify,
GET_LIST,
} from 'react-admin';
import jsonExport from 'jsonexport/dist';

const ExportButton = ({ sort, filter, maxResults = 1000, resource }) => {
const dataProvider = useDataProvider();
const notify = useNotify();
const payload = { sort, filter, pagination: { page: 1, perPage: maxResults }}
const handleClick = dataProvider(GET_LIST, resource, payload)
.then(({ data }) => jsonExport(data, (err, csv) => downloadCSV(csv, resource)))
.catch(error => notify('ra.notification.http_error', 'warning'));

return (
<Button
label="Export"
onClick={handleClick}
/>
);
};
```
7 changes: 3 additions & 4 deletions docs/List.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ const PostList = props => (
)
```

In many cases, you'll need more than simple object manipulation. You'll need to *augment* your objects based on relationships. For instance, the export for comments should include the title of the related post - but the export only exposes a `post_id` by default. For that purpose, the exporter receives a `fetchRelatedRecords` function as second parameter. It fetches related records using your `dataProvider` and Redux, and returns a promise.
In many cases, you'll need more than simple object manipulation. You'll need to *augment* your objects based on relationships. For instance, the export for comments should include the title of the related post - but the export only exposes a `post_id` by default. For that purpose, the exporter receives a `fetchRelatedRecords` function as second parameter. It fetches related records using your `dataProvider` and the `GET_MANY` verb, and returns a promise.

Here is an example for a Comments exporter, fetching related Posts:

Expand All @@ -194,6 +194,7 @@ import { List, downloadCSV } from 'react-admin';
import jsonExport from 'jsonexport/dist';

const exporter = (records, fetchRelatedRecords) => {
// will call dataProvider(GET_MANY, 'posts', { ids: records.map(record => record.post_id) }), ignoring duplicate and empty post_id
fetchRelatedRecords(records, 'post_id', 'posts').then(posts => {
const data = records.map(record => ({
...record,
Expand All @@ -214,9 +215,7 @@ const CommentList = props => (
)
```

Under the hood, `fetchRelatedRecords()` uses react-admin's sagas, which trigger the loading spinner while loading. As a bonus, all the records fetched during an export are kepts in the main Redux store, so further browsing the admin will be accelerated.

**Tip**: If you need to call another `dataProvider` verb in the exporter, take advantage of the third parameter passed to the function: `dispatch()`. It allows you to call any Redux action. Combine it with [the `callback` side effect](./Actions.md#custom-sagas) to grab the result in a callback.
**Tip**: If you need to call another verb in the exporter, take advantage of the third parameter passed to the function: it's the `dataProvider` function.

**Tip**: The `<ExportButton>` limits the main request to the `dataProvider` to 1,000 records. If you want to increase or decrease this limit, pass a `maxResults` prop to the `<ExportButton>` in a custom `<ListActions>` component, as explained in the previous section.

Expand Down
162 changes: 0 additions & 162 deletions packages/ra-ui-materialui/src/button/ExportButton.js

This file was deleted.

Loading

0 comments on commit 9b08ceb

Please sign in to comment.