single-spa
single-spa copied to clipboard
Is there a way to avoid the reload of a micro-frontend when history.pushState is called and the URL will change ?
Describe the bug or question I saw many other issues has been opened (#484 #936) but I'm feeling I haven't a different use case that isn't working properly.
I have an application composed by many microfrontends and based on the current URL different microfrontends are rendered on screen. I need to update the query params in order to save the current state of the user interaction into the URL (e.g. which tab is the user visiting, if a modal is open, etc). This feature is needed to let the user share its URL allowing a second user that will open that URL to see everything the first user was seeing.
I got that if I call window.history.pushState
changing also the URL (window.history.pushState({path: newURL}, '', newURL )
) , single-spa will trigger a popstate
event that will re-render the microfrontend. This lead to a poor UX experience because re-rendering all the microfrontend every time a query params is updated lead to a very slow UI update (e.g. the opening of the new tab is slow, the opening of the modal is slow, etc).
Expected behavior Having a way to update the query params without triggering the re-render of the microfrontend, nor the current one neither one of the others microfrontend rendered on screen.
Suggestion
Maybe it's just a naive suggestion but, could be enough to have a single-spa method that can do that ? So instead of calling window.history.pushState(...)
we can could call singleSpa.pushState(...)
.
Does the urlRerouteOnly
argument work for you in this situation?
https://single-spa.js.org/docs/api#start
@frehner No, unfortunately it doesn't. I had set that in my root-microfrontend
(start({ urlRerouteOnly: true });
) but I'm still getting the refresh of the whole application. Talking about useRerouteOnly
, I read here that is useful when the URL does not change and in my use case it change because I have to save there a piece of the "state" of the application.
(For the ones the are interested, I'm handling with redux the UI update while I'm saving on the URL all the query param useful to rebuild the state app if another user open the link I'll send to him)
I also tried to use the navigateToUrl
method but it internally use window.history.pushState
so I ended up to have the same unwanted re-render.
Like we have the navigateToUrl
would be nice to have or:
- An argument for that method that tells single-spa to not re-render the whole application
- A different method that change the URL without triggering the re-render of the whole application
Is there any update ?
I tested this using the Planets react microfrontend. I added console.logs in root.component.js and in planets-page.component.js. I see what I expected: the log in root.component is logged once when the application mounts, and then the log in planets-page.component logs once on mount and then again on every navigation change. This is how react-router works from what I understand. It listens to url changes and so causes the component to rerender with the latest route as props (what the Route component does). Does this match what you're expecting?
@filoxo If I navigate clicking some UI element into the UI yes, because under the hood probably there is a history.push
call, but if I'm using window.history.pushState
as fas as I understand the UI shouldn't re-render. If I try to call the window.history.pushState
in a plain react project the UI doesn't re-render, in my single-spa project it does (I'm making this tests using che console from the Chrome dev tool).
@filoxo I'm posting here the GIF of the latest test I made in my project. I'm using a project of mine made using create-react-app and the single-spa microfrontend example overriding the planets microfrontend from localhost. I'm seeing that all the component contained into <BrowserRouter/>
are re-rendered when I call an window.history.push
. These re-renders won't happen in the create-react-app project.
navigate clicking some UI element into the UI
I did not navigate with any UI, and used window.history.pushState
exactly like you'd shown in this gif shared on Slack.
(copying from Slack so this information is not lost to history)
just came across this while researching react 18. seems maybe pertinent to this issue we've been looking at https://github.com/remix-run/react-router/issues/7634
Full conversation here: https://single-spa.slack.com/archives/C8R6U7MT7/p1645123174915319
Closing this, as it appears the conversation has dried up and the last message may have solve the issue. Feel free to respond if that's not the case.
The solution is in slack - if there is a solution there, it should be shared here
The solution is in slack - if there is a solution there, it should be shared here
Also looking for a solution, unfortunately Slack does not show messages older than 90 days, so impossible to see the conversation.
Please share the solution here if it exists