Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Doc] Improve the side effect hooks documentation #6388

Merged
merged 2 commits into from
Jun 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 146 additions & 4 deletions docs/Actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -620,10 +620,152 @@ const ApproveButton = ({ record }) => {

Fetching data is called a *side effect*, since it calls the outside world, and is asynchronous. Usual actions may have other side effects, like showing a notification, or redirecting the user to another page. React-admin provides the following hooks to handle most common side effects:

- `useNotify`: Return a function to display a notification. The arguments should be a message (it can be a translation key), a level (either `info`, `success` or `warning`), an `options` object to pass to the `translate` function (in the case of the default i18n provider, using Polyglot.js, it will be the interpolation options used for passing variables), a boolean to set to `true` if the notification should contain an "undo" button and a number corresponding to the notification duration.
- `useRedirect`: Return a function to redirect the user to another page. The arguments should be the path to redirect the user to, and the current `basePath`.
- `useRefresh`: Return a function to force a rerender of the current view (equivalent to pressing the Refresh button).
- `useUnselectAll`: Return a function to unselect all lines in the current `Datagrid`. Pass the name of the resource as argument.
- [`useNotify`](#usenotify): Return a function to display a notification.
- [`useRedirect`](#useredirect): Return a function to redirect the user to another page.
- [`useRefresh`](#userefresh): Return a function to force a rerender of the current view (equivalent to pressing the Refresh button).
- [`useUnselectAll`](#useunselectall): Return a function to unselect all lines in the current `Datagrid`.

### `useNotify`

This hook returns a function that displays a notification in the bottom of the page.

```jsx
import { useNotify } from 'react-admin';

const NotifyButton = () => {
const notify = useNotify();
const handleClick = () => {
notify(`Comment approved`, 'success');
}
return <button onClick={handleClick}>Notify</button>;
};
```

The callback takes 5 arguments:
- the message to display
- the level of the notification (`info`, `success` or `warning` - the default is `info`)
- an `options` object to pass to the `translate` function (because notificatoin messages are translated if your admin has an `i18nProvider`). It is useful for inserting variables into the translation.
- an `undoable` boolean. Set it to `true` if the notification should contain an "undo" button
- a `duration` number. Set it to `0` if the notification should not be dismissable.

Here are more examples of `useNotify` calls:

```jsx
// notify a warning
notify(`This is a warning`, 'warning');
// pass translation arguments
notify('item.created', 'info', { resource: 'post' });
// send an undoable notification
notify('Element updated', 'info', undefined, true);
```

**Tip**: When using `useNotify` as a side effect for an `undoable` Edit form, you MUST set the fourth argument to `true`, otherwise the "undo" button will not appear, and the actual update will never occur.

```jsx
import * as React from 'react';
import { useNotify, Edit, SimpleForm } from 'react-admin';

const PostEdit = props => {
const notify = useNotify();

const onSuccess = () => {
notify(`Changes saved`, undefined, undefined, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably ask for a single option object instead of 5 args imo. Maybe we can support both until we deprecate the 5 args signature?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea, but let's do it in another PR

};

return (
<Edit undoable onSuccess={onSuccess} {...props}>
<SimpleForm>
...
</SimpleForm>
</Edit>
);
}
```

### `useRedirect`

This hook returns a function that redirects the user to another page.

```jsx
import { useRedirect } from 'react-admin';

const DashboardButton = () => {
const redirect = useRedirect();
const handleClick = () => {
redirect('/dashboard');
}
return <button onClick={handleClick}>Dashboard</button>;
};
```

The callback takes 3 arguments:
- the page to redirect the user to ('list', 'create', 'edit', 'show', or a custom path)
- the current `basePath`
- the `id` of the record to redirect to (if any)

Here are more examples of `useRedirect` calls:

```jsx
// redirect to the post list page
redirect('list', '/posts');
// redirect to the edit page of a post:
redirect('edit', '/posts', 1);
// redirect to the post creation page:
redirect('create', '/posts');
```

Note that `useRedirect` doesn't allow to redirect to pages outside the current React app. For that, you should use `document.location`.

### `useRefresh`

This hook returns a function that forces a rerender of the current view.

```jsx
import { useRefresh } from 'react-admin';

const RefreshButton = () => {
const refresh = useRefresh();
const handleClick = () => {
refresh();
}
return <button onClick={handleClick}>Refresh</button>;
};
```

To make this work, react-admin stores a `version` number in its state. The `useDataProvider()` hook uses this `version` in its effect dependencies. Also, page components use the `version` as `key`. The `refresh` callback increases the `version`, which forces a re-execution all queries based on the `useDataProvider()` hook, and a rerender of all components using the `version` as key.

This means that you can make any component inside a react-admin app refreshable by using the right key:

```jsx
import * as React from 'react';
import { useVersion } from 'react-admin';

const MyComponent = () => {
const version = useVersion();
return <div key={version}>
...
</div>;
};
```

The callback takes 1 argument:
- `hard`: when set to true, the callback empties the cache, too

### `useUnselectAll`

This hook returns a function that unselects all lines in the current `Datagrid`. Pass the name of the resource as argument.

```jsx
import { useUnselectAll } from 'react-admin';

const UnselectAllButton = () => {
const unselectAll = useUnselectAll();
const handleClick = () => {
unselectAll('posts');
}
return <button onClick={handleClick}>Unselect all</button>;
};
```

## Handling Side Effects In Other Hooks

Expand Down
7 changes: 4 additions & 3 deletions docs/Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,14 @@ title: "Reference"
* `useLogoutIfAccessDenied`
* [`useMediaQuery`](./Theming.md#usemediaquery-hook)
* [`useMutation`](./Actions.md#usemutation-hook)
* [`useNotify`](./Actions.md#handling-side-effects-in-usedataprovider)
* [`useNotify`](./Actions.md#usenotify)
* `usePaginationState`
* [`usePermissions`](./Authentication.md#usepermissions-hook)
* [`usePreferences`](https://marmelab.com/ra-enterprise/modules/ra-preferences#usepreferences-reading-and-writing-user-preferences)<img class="icon" src="./img/premium.svg" />
* [`useQuery`](./Actions.md#usequery-hook)
* [`useQueryWithStore`](./Actions.md#usequerywithstore-hook)
* [`useRedirect`](./Actions.md#handling-side-effects-in-usedataprovider)
* [`useRedirect`](./Actions.md#useredirect)
* [`useRefresh`](./Actions.md#userefresh)
* [`useResourceAppLocation`](https://marmelab.com/ra-enterprise/modules/ra-navigation#useresourceapplocation-access-current-resource-app-location)<img class="icon" src="./img/premium.svg" />
* `useReference`
* `useReferenceArrayFieldController`
Expand All @@ -206,7 +207,7 @@ title: "Reference"
* [`useUpdate`](./Actions.md#useupdate)
* `useUpdateLoading`
* [`useUpdateMany`](./Actions.md#useupdatemany)
* [`useUnselectAll`](./Actions.md#handling-side-effects-in-usedataprovider)
* [`useUnselectAll`](./Actions.md#useunselectall)
* [`useWarnWhenUnsavedChanges`](./CreateEdit.md#warning-about-unsaved-changes)
* `useVersion`
* [`withDataProvider`](./Actions.md#legacy-components-query-mutation-and-withdataprovider)
Expand Down