Closed goenning closed 5 years ago
Hey @goenning,
I made an example with React.lazy
and Suspense
Now let me give you more details. When you call for instance toast('Hello')
, the notification is added to a queue. So you can even call toast('Hello')
several time without mounting the ToastContainer
.
Then, when the ToastContainer
is mounted later all the queued notifications will be displayed.
Is that what you are looking for ?
Very close, but not exactly.
In your example the bundle that contains ToastContainer will be loaded async, which is a good start, but it'll still be loaded and mounted even when there was no toast('Hello')
call.
What I'm trying to achieve is:
1) some component will call toast('Hello')
and internally it'll add the notification to the queue
2) trigger SOMETHING
that will download the bundle that contains ToastContainer, wait for it to load and mount it to the DOM
3) whenever mounted, show notification
I think this package has 1 & 3 builtin. Number 2 is achieved with Suspense and Lazy, but how to trigger that?
@goenning so you want to mount the ToastContainer
only if toast('hello')
is called. If toast
is not called no need to mount the container right ?
Exactly!
I updated the sample using setState
For a real application you may need to do that at several place. If you are using a state management library like mobx or redux it will be even easier to implement. For instance with mobx one could do:
class UiStore {
hasContainer = false;
notify(content, options){
if(! this.hasContainer){
this.hasContainer = true;
}
toast(content, options);
}
}
Interesting. Something just came to my mind now. To achieve code split, we need to wrap both toast and ToastContainer on an async module. Because if we import "react-toastify" on any other component (like App.js on your example), webpack will bundle it as sync bundle, which defeats the purpose of code splitting.
But you gave me some ideas, I'll try it out, see how it goes and update this thread. Thanks!
You're welcome!
For anyone interested: https://github.com/goenning/example-react-toastify-code-split
This project will only load react-toastify library when the user clicks on the logo for the first time.
If react-toastify supported React Portals, the solution would be slightly simpler, as we wouldn't need to mount the ToastContainer. Maybe that could be a new feature request? 😄
Hey @goenning,
How will React.portal
could make things simpler? Even with the portal the ToastContainer
will be mounted sooner or later. Am I missing something?
I would love to hear more about your idea.
Well, I don't know much about react-toastify internals, but as far as I understood,toast
function queues the notifications and ToastContainer
consumes them and renders it as a child.
If renderTo
was added to toast
options, like:
toast("Hello World", {
// ...options
renderTo: "root-toastify"
}
toast
could then check if renderTo
property is defined, if so, then it wouldn't queue the notification, but actually append it to the DOM node with id root-toastify
using React Portals, thus completely bypassing the ToastContainer.
I haven't done much with React Portals, but I guess that's what it is for.
@goenning I really like the idea of having a renderTo
option. This open a lot of possibility like having multiple container which is not supported for the moment.
This also allow to render the ToastContainer
only when needed, which is what you are looking for.
I see one downside with this approach. Some props are only available for the ToastContainer
and we will lose the ability to define them.
So far, only 2 props are concerned: rtl
andnewestOnTop
. Anyway this can be solved easily
Thank you for the brilliant idea(renderTo
)! I'll try to play around with it.
Just for reference, I have implemented it on a real app and it works 💯
This is how we did it https://github.com/getfider/fider/pull/645
This is very neat. I'll probably start to work on the next release in 2 weeks. I'll leave the issue open with a label how to. Thank you for sharing your solution
Hey @goenning,
For the next release the ToastContainer
will be optional. The container will be mounted on demand only.
Is there any way to use react-toastify with React.lazy?
My scenario is that there are very few places we show the toaster, probably only 5% of the users ever see a toaster. As of now, we push react-toastify on the main bundle, forcing everyone to download it.
I'm thinking on how can we use React.lazy to solve this, but I can't don't know how would I do it, mostly because the toast function requires to be on the DOM when it's called.
Any thoughts on how to achieve this?
Thanks!