Skip to content

Commit 44b52e4

Browse files
authored
Merge pull request #8136 from marmelab/fix-usenotify-triggers-rerenders
Fix useNotify triggers useless rerenders
2 parents 2165aad + 4d641e2 commit 44b52e4

6 files changed

+72
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createContext } from 'react';
2+
3+
import { NotificationPayload } from './types';
4+
5+
export const AddNotificationContext = createContext<
6+
(notification: NotificationPayload) => void
7+
>(() => {});

packages/ra-core/src/notification/NotificationContextProvider.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useState, useCallback, useMemo } from 'react';
33

44
import { NotificationPayload } from './types';
55
import { NotificationContext } from './NotificationContext';
6+
import { AddNotificationContext } from './AddNotificationContext';
67

78
export const NotificationContextProvider = ({ children }) => {
89
const [notifications, setNotifications] = useState<NotificationPayload[]>(
@@ -33,9 +34,13 @@ export const NotificationContextProvider = ({ children }) => {
3334
[notifications] // eslint-disable-line react-hooks/exhaustive-deps
3435
);
3536

37+
// we separate the addNotification context to avoid rerendering all components
38+
// that depend on useNotify when a notification is dispatched
3639
return (
3740
<NotificationContext.Provider value={contextValue}>
38-
{children}
41+
<AddNotificationContext.Provider value={addNotification}>
42+
{children}
43+
</AddNotificationContext.Provider>
3944
</NotificationContext.Provider>
4045
);
4146
};
+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
export * from './types';
2-
export * from './useNotify';
1+
export * from './AddNotificationContext';
32
export * from './NotificationContext';
43
export * from './NotificationContextProvider';
4+
export * from './types';
5+
export * from './useAddNotificationContext';
56
export * from './useNotificationContext';
7+
export * from './useNotify';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { useContext } from 'react';
2+
import { AddNotificationContext } from './AddNotificationContext';
3+
4+
export const useAddNotificationContext = () =>
5+
useContext(AddNotificationContext);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import * as React from 'react';
2+
import { useNotify } from './useNotify';
3+
import { useNotificationContext } from './useNotificationContext';
4+
import { NotificationContextProvider } from './NotificationContextProvider';
5+
6+
export default {
7+
title: 'ra-core/useNotify',
8+
};
9+
10+
const Button = () => {
11+
const notify = useNotify();
12+
const handleClick = React.useCallback(() => {
13+
notify('hello');
14+
}, [notify]);
15+
return <button onClick={handleClick}>Notify</button>;
16+
};
17+
18+
const Notifications = () => {
19+
const { notifications } = useNotificationContext();
20+
return (
21+
<ul>
22+
{notifications.map(({ message }, id) => (
23+
<li key={id}>{message}</li>
24+
))}
25+
</ul>
26+
);
27+
};
28+
29+
export const Basic = () => (
30+
<NotificationContextProvider>
31+
<Button />
32+
<Notifications />
33+
</NotificationContextProvider>
34+
);
35+
36+
export const ManyListeners = () => {
37+
const times = new Array(100).fill(0);
38+
return (
39+
<NotificationContextProvider>
40+
{times.map((_, index) => (
41+
<Button key={index} />
42+
))}
43+
<div>
44+
<Notifications />
45+
</div>
46+
</NotificationContextProvider>
47+
);
48+
};

packages/ra-core/src/notification/useNotify.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useCallback } from 'react';
22

3-
import { useNotificationContext } from './useNotificationContext';
3+
import { useAddNotificationContext } from './useAddNotificationContext';
44
import { NotificationType, NotificationOptions } from './types';
55

66
/**
@@ -19,7 +19,7 @@ import { NotificationType, NotificationOptions } from './types';
1919
* notify('Post renamed', { type: 'info', undoable: true })
2020
*/
2121
export const useNotify = () => {
22-
const { addNotification } = useNotificationContext();
22+
const addNotification = useAddNotificationContext();
2323
return useCallback(
2424
(
2525
message: string,

0 commit comments

Comments
 (0)