How to access toasts state from outside of React function component?
Hi, first off thanks for maintaining this really nifty, well-designed library!
I recently ran into a use case where some code outside of a React component needed to know if a particular toast was visible.
AFAIK the only way to access all the toasts' state is via the useToasterStore hook, so to expose the list of visible toast IDs to the outside, I had to manually render a component and expose it's state via a wrapping Promise:
import { Fragment } from 'react';
import ReactDOM from 'react-dom/client';
import toast, { ToastPosition, useToasterStore } from 'react-hot-toast';
import waitForTimers from 'wait-for-timers';
import { reportSentryError } from './sentry';
// Very hacky way to get toast ids by temporarily rendering component to use hook, but it works
export function getToastIds(): Promise<string[]> {
return new Promise((resolve) => {
// Should never take longer than a few ms
const cancelTimeout = waitForTimers([10], () => {
reportSentryError('getToastIds render too slow');
resolve([]);
});
// Temporarily render component to call custom hook & get toast ids
const root = ReactDOM.createRoot(document.createElement('div'));
root.render(
<ToasterStoreComponent
setIds={(ids: string[]) => {
cancelTimeout();
resolve(ids);
}}
/>
);
});
}
// Only used to call custom hook, doesn't render anything
function ToasterStoreComponent({ setIds }: { setIds: (result: string[]) => void }) {
const { toasts } = useToasterStore();
setIds(toasts.map((toast) => toast.id));
return <Fragment />;
}
I do not love this solution for many reasons, and today discovered that occasionally it takes over 10ms for this render to happen, slowing down my app.
Any chance we could expose the return value of useToasterStore or allow registering a custom listener? Really any way of accessing this data without having to trigger a React function component render.
Thanks!
Hi, as far as I understand your question correctly – you need a separate component to know when a specific toast is in the DOM. Looking at the API, the way I would do this is by:
- Setting up custom toast component using the
useToast()hook. - Attaching a
refto the component. - Using the
refto see if the component is in the DOM currently by adding it to some sort of global context.
Hope this helps.