Skip to content

useSubscribeToRecord

This specialized version of useSubscribe subscribes to events concerning a single record.

This feature requires a valid Enterprise Edition subscription.

Terminal window
npm install --save @react-admin/ra-core-ee
# or
yarn add @react-admin/ra-core-ee

The hook expects a callback function as its only argument, as it guesses the record and resource from the current context. The callback will be executed whenever an event is published on the resource/[resource]/[recordId] topic.

For instance, the following component displays a message when the record is updated by someone else:

const WarnWhenUpdatedBySomeoneElse = () => {
const [open, setOpen] = useState(false);
const [author, setAuthor] = useState<string | null>(null);
const handleClose = () => {
setOpen(false);
};
const { refetch } = useEditContext();
const refresh = () => {
refetch();
handleClose();
};
const {
formState: { isDirty },
} = useFormContext();
useSubscribeToRecord((event: Event) => {
if (event.type === 'edited') {
if (isDirty) {
setOpen(true);
setAuthor(event.payload.user);
} else {
refetch();
}
}
});
return open ? (
<div className="flex flex-col gap-4">
<p>
Post Updated by {author}
</p>
<p>
Your changes and their changes may conflict. What do you
want to do?
</p>
<div className="flex gap-4">
<button onClick={handleClose}>Keep my changes</button>
<button onClick={refresh}>
Get their changes (and lose mine)
</button>
</div>
</div>
) : null;
};
const PostEdit = () => (
<EditBase>
<Form>
{/* Inputs... */}
<WarnWhenUpdatedBySomeoneElse />
</Form>
</EditBase>
);

useSubscribeToRecord reads the current resource and record from the ResourceContext and RecordContext respectively. In the example above, the notification is displayed when the app receives an event on the resource/books/123 topic.

Just like useSubscribe, useSubscribeToRecord unsubscribes from the topic when the component unmounts.

Tip: In the example above, <Show> creates the RecordContext- that’s why the useSubscribeToRecord hook is used in its child component instead of in the <BookShow> component.

You can provide the resource and record id explicitly if you are not in such contexts:

useSubscribeToRecord(
event => {
/* ... */
},
'posts',
123
);

Tip: If your reason to subscribe to events on a record is to keep the record up to date, you should use the useGetOneLive hook instead.

PropRequiredTypeDefaultDescription
callbackRequiredfunction-The callback to execute when an event is received.
resourceOptionalstring-The resource to subscribe to. Defaults to the resource in the ResourceContext.
recordIdOptionalstring-The record id to subscribe to. Defaults to the id of the record in the RecordContext.
optionsOptionalobject-The subscription options.

Whenever an event is published on the resource/[resource]/[recordId] topic, the function passed as the first argument will be called with the event as a parameter.

const [open, setOpen] = useState(false);
const [author, setAuthor] = useState<string | null>(null);
const { refetch } = useEditContext();
const {
formState: { isDirty },
} = useFormContext();
useSubscribeToRecord((event: Event) => {
if (event.type === 'edited') {
if (isDirty) {
setOpen(true);
setAuthor(event.payload.user);
} else {
refetch();
}
}
});

Tip: Memoize the callback using useCallback to avoid unnecessary subscriptions/unsubscriptions.

const [open, setOpen] = useState(false);
const [author, setAuthor] = useState<string | null>(null);
const { refetch } = useEditContext();
const {
formState: { isDirty },
} = useFormContext();
const handleEvent = useCallback(
(event: Event) => {
if (event.type === 'edited') {
if (isDirty) {
setOpen(true);
setAuthor(event.payload.user);
} else {
refetch();
}
}
},
[isDirty, refetch, setOpen, setAuthor]
);
useSubscribeToRecord(handleEvent);

Just like for useSubscribe, the callback function receives an unsubscribe callback as its second argument. You can call it to unsubscribe from the topic after receiving a specific event.

useSubscribeToRecord((event: Event, unsubscribe) => {
if (event.type === 'deleted') {
// do something
unsubscribe();
}
if (event.type === 'edited') {
if (isDirty) {
setOpen(true);
setAuthor(event.payload.user);
} else {
refetch();
}
}
});

The options object can contain the following properties:

  • enabled: Whether to subscribe or not. Defaults to true
  • once: Whether to unsubscribe after the first event. Defaults to false.
  • unsubscribeOnUnmount: Whether to unsubscribe on unmount. Defaults to true.

See useSubscribe for more details.

The record id to subscribe to. By default, useSubscribeToRecord builds the topic it subscribes to using the id of the record in the RecordContext. But you can override this behavior by passing a record id as the third argument.

// will subscribe to the 'resource/posts/123' topic
useSubscribeToRecord(
event => {
/* ... */
},
'posts',
123
);

Note that if you pass a null record id, the hook will not subscribe to any topic.

The resource to subscribe to. By default, useSubscribeToRecord builds the topic it subscribes to using the resource in the ResourceContext. But you can override this behavior by passing a resource name as the second argument.

// will subscribe to the 'resource/posts/123' topic
useSubscribeToRecord(
event => {
/* ... */
},
'posts',
123
);

Note that if you pass an empty string as the resource name, the hook will not subscribe to any topic.