Skip to content

Commit

Permalink
Merge pull request #8136 from marmelab/fix-usenotify-triggers-rerenders
Browse files Browse the repository at this point in the history
Fix useNotify triggers useless rerenders
  • Loading branch information
slax57 committed Sep 5, 2022
2 parents 2165aad + 4d641e2 commit 44b52e4
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 5 deletions.
7 changes: 7 additions & 0 deletions packages/ra-core/src/notification/AddNotificationContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createContext } from 'react';

import { NotificationPayload } from './types';

export const AddNotificationContext = createContext<
(notification: NotificationPayload) => void
>(() => {});
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useState, useCallback, useMemo } from 'react';

import { NotificationPayload } from './types';
import { NotificationContext } from './NotificationContext';
import { AddNotificationContext } from './AddNotificationContext';

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

// we separate the addNotification context to avoid rerendering all components
// that depend on useNotify when a notification is dispatched
return (
<NotificationContext.Provider value={contextValue}>
{children}
<AddNotificationContext.Provider value={addNotification}>
{children}
</AddNotificationContext.Provider>
</NotificationContext.Provider>
);
};
6 changes: 4 additions & 2 deletions packages/ra-core/src/notification/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export * from './types';
export * from './useNotify';
export * from './AddNotificationContext';
export * from './NotificationContext';
export * from './NotificationContextProvider';
export * from './types';
export * from './useAddNotificationContext';
export * from './useNotificationContext';
export * from './useNotify';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { useContext } from 'react';
import { AddNotificationContext } from './AddNotificationContext';

export const useAddNotificationContext = () =>
useContext(AddNotificationContext);
48 changes: 48 additions & 0 deletions packages/ra-core/src/notification/useNotify.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as React from 'react';
import { useNotify } from './useNotify';
import { useNotificationContext } from './useNotificationContext';
import { NotificationContextProvider } from './NotificationContextProvider';

export default {
title: 'ra-core/useNotify',
};

const Button = () => {
const notify = useNotify();
const handleClick = React.useCallback(() => {
notify('hello');
}, [notify]);
return <button onClick={handleClick}>Notify</button>;
};

const Notifications = () => {
const { notifications } = useNotificationContext();
return (
<ul>
{notifications.map(({ message }, id) => (
<li key={id}>{message}</li>
))}
</ul>
);
};

export const Basic = () => (
<NotificationContextProvider>
<Button />
<Notifications />
</NotificationContextProvider>
);

export const ManyListeners = () => {
const times = new Array(100).fill(0);
return (
<NotificationContextProvider>
{times.map((_, index) => (
<Button key={index} />
))}
<div>
<Notifications />
</div>
</NotificationContextProvider>
);
};
4 changes: 2 additions & 2 deletions packages/ra-core/src/notification/useNotify.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback } from 'react';

import { useNotificationContext } from './useNotificationContext';
import { useAddNotificationContext } from './useAddNotificationContext';
import { NotificationType, NotificationOptions } from './types';

/**
Expand All @@ -19,7 +19,7 @@ import { NotificationType, NotificationOptions } from './types';
* notify('Post renamed', { type: 'info', undoable: true })
*/
export const useNotify = () => {
const { addNotification } = useNotificationContext();
const addNotification = useAddNotificationContext();
return useCallback(
(
message: string,
Expand Down

0 comments on commit 44b52e4

Please sign in to comment.