timolins / react-hot-toast

Smoking Hot React Notifications 🔥
https://react-hot-toast.com
MIT License
9.66k stars 319 forks source link

Possible to use custom toasts from a custom component library in a separate project/app? #223

Closed 25747 closed 1 year ago

25747 commented 2 years ago

I have an external component library where I've built and tested a custom toast function that works great. My function, called toastAlert gets called with the toast message and then calls toast.custom() in order to use a custom styled toast component. Basically I'm just abstracting the boilerplate of having to call toast.custom with a custom component every time i want it.

in my custom library:

import toast from 'react-hot-toast';
import CustomStyledToast from './';

export const toastAlert = (message) => {
  toast.custom((t) => {
    <CustomStyledToast t={t} message={message} />
  }
}

example of custom toast working in storybook: image

It's perfect in my component library and storybook, but when I try to import my toastAlert function into my actual app, nothing happens on calling the function. (my storybook implementation is functionally identical to the App example below)

in my app:

import { Toaster } from 'react-hot-toast';
import toastAlert from 'custom-library';

const App = () => {
  return (
    <>
      <button onClick={() => toastAlert('custom toast message')>Click for toast</button>
      <Toaster />
    </>
  )
}

There are no errors or anything when I call toastAlert, simply nothing happens. If I import the standard toast function from react-hot-toast, the standard toasts work fine.

If I move all of my custom toastAlert code into my app files, it works perfectly, so there is something I don't understand that's getting in the way when trying to use a toast call from a separate component library/repo. Is what I'm trying to do possible, or is there some sort of 'binding' (for lack of a better word) between the toast function and the component where they must be imported into the same project to work together?

this appears to be related to https://github.com/timolins/react-hot-toast/issues/108

Joshuapwilley commented 1 year ago

I also ran into this issue, and I suspect this line is the culprit: https://github.com/timolins/react-hot-toast/blob/main/src/components/toaster.tsx#L13

I'm not entirely sure what it's doing, but it's likely manipulating the createElement function, and that function's identity will likely be different when used in an external library.

You can export the component from your custom lib and use that reference in your app as a workaround. Importantly, your app will not import directly from 'react-hot-toast' but instead from your custom lib.

custom library

import toast, { Toaster } from 'react-hot-toast';
import CustomStyledToast from './';

export { Toaster }; // <-- Export <Toaster /> component from your custom lib

export const toastAlert = (message) => {
  toast.custom((t) => {
    <CustomStyledToast t={t} message={message} />
  }
}

app

// Only import from your custom lib
import { toastAlert, Toaster } from 'custom-library';

const App = () => {
  return (
    <>
      <button onClick={() => toastAlert('custom toast message')>Click for toast</button>
      <Toaster />
    </>
  )
}

This solution worked for me! I hope it helps.

25747 commented 1 year ago

Thanks very much for that! I won't be able to test this out for a while, but after glancing through the goober docs the reasoning makes sense.

LeandroPereiraDaCruz commented 1 month ago

I had the same problem.

But instead of exporting the Toaster component in my external lib.

I passed the toast instance via props to my lib function.

Something like that:

import type ToastInstance from 'react-hot-toast';

export default function useFoo({ toast }: { toast: ToastInstance }) {
    useEffect(()=> {
        toast.loading('It works here');
    });
}