Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Suspense and react-toastify #276

Closed
goenning opened this issue Nov 10, 2018 · 14 comments
Closed

React Suspense and react-toastify #276

goenning opened this issue Nov 10, 2018 · 14 comments
Assignees
Labels

Comments

@goenning
Copy link

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!

@fkhadra
Copy link
Owner

fkhadra commented Nov 11, 2018

Hey @goenning,

I made an example with React.lazy and Suspense
Edit 2nmnvrn6r

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 ?

@fkhadra fkhadra self-assigned this Nov 11, 2018
@goenning
Copy link
Author

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?

@fkhadra
Copy link
Owner

fkhadra commented Nov 11, 2018

@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 ?

@goenning
Copy link
Author

Exactly!

@fkhadra
Copy link
Owner

fkhadra commented Nov 11, 2018

I updated the sample using setState
Edit 2nmnvrn6r

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); 
  }
}

@goenning
Copy link
Author

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!

@fkhadra
Copy link
Owner

fkhadra commented Nov 11, 2018

You're welcome!

@goenning
Copy link
Author

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? 😄

@fkhadra
Copy link
Owner

fkhadra commented Nov 12, 2018

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.

@goenning
Copy link
Author

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.

@fkhadra
Copy link
Owner

fkhadra commented Nov 12, 2018

@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.

@goenning
Copy link
Author

Just for reference, I have implemented it on a real app and it works 💯

kapture 2018-11-24 at 10 28 27

This is how we did it getfider/fider#645

@fkhadra
Copy link
Owner

fkhadra commented Nov 24, 2018

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

@fkhadra fkhadra added How to and removed question labels Nov 24, 2018
@fkhadra
Copy link
Owner

fkhadra commented Mar 13, 2019

Hey @goenning,

For the next release the ToastContainer will be optional. The container will be mounted on demand only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants