single-spa icon indicating copy to clipboard operation
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 ?

Open lucataglia opened this issue 3 years ago • 9 comments

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(...).

lucataglia avatar Feb 17 '22 18:02 lucataglia

Does the urlRerouteOnly argument work for you in this situation?

https://single-spa.js.org/docs/api#start

frehner avatar Feb 17 '22 20:02 frehner

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

lucataglia avatar Feb 17 '22 22:02 lucataglia

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:

  1. An argument for that method that tells single-spa to not re-render the whole application
  2. A different method that change the URL without triggering the re-render of the whole application

lucataglia avatar Feb 18 '22 10:02 lucataglia

Is there any update ?

lucataglia avatar Mar 21 '22 09:03 lucataglia

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 avatar Mar 30 '22 17:03 filoxo

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

lucataglia avatar Mar 31 '22 07:03 lucataglia

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

singleSpaReRenderIssue

lucataglia avatar Mar 31 '22 07:03 lucataglia

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.

filoxo avatar Mar 31 '22 08:03 filoxo

(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

filoxo avatar Apr 19 '22 19:04 filoxo

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.

eedrah avatar Aug 26 '22 04:08 eedrah

The solution is in slack - if there is a solution there, it should be shared here

onionhammer avatar Sep 13 '22 20:09 onionhammer

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.

mikkelsiercke avatar Feb 21 '23 15:02 mikkelsiercke

Please share the solution here if it exists

hritikb27 avatar Sep 04 '23 05:09 hritikb27