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

Page is refreshed by calling history.go(), while history.back() isn't #824

Closed
Carduelis opened this issue Aug 4, 2020 · 6 comments
Closed

Comments

@Carduelis
Copy link

We have iframe based micro-frontends. There is a need of changing the state of the inside app from outside one without full-reloading of the inside one.
There is <BrowserRouter /> which uses Native History API.

I have tested the behavior on single app without any iframes.

When I click anchors in the app, React router doesn't refresh the whole app, and replaces parts of the app. In my case -- it's pagination.

I can call window.history.back() and it will not trigger page refresh.
The same, I can do window.history.go(-1) and it will not trigger page referesh.

Then I decided what if I make window.history.pushState(null, null, 'page/2') and call window.history.go() -- page will be refreshed from scratch.

I can solve my task by replacing BrowserRouter by Router and exposing history object to window.ReactRouterHistory, but I think it's too much, when I can do window.history.back() without a page refresh.

Is it a bug? Why the page is fully refreshed by go(), but isn't when go(-1)?
Is there a proper way to do this?

Thank you!

@StringEpsilon
Copy link

StringEpsilon commented Aug 4, 2020

Can you clarify what exactly you're doing?

If you invoke window.history.go() without any parameters, that will cause a page refresh, same as window.history.go(0). That behavior is part of specifications, as described here: https://developer.mozilla.org/en-US/docs/Web/API/History/go

window.history.back() is essentially just an alias for window.history.go(-1). In the history library, it's .goBack and also just an alias.

I'm not sure why you call go without a parameter. If you want to go back, then you have to call go(-1). And also: Why are you bypassing the history library in the first place? react-router provides you easy access to the history object it uses.

@Carduelis
Copy link
Author

Carduelis commented Aug 5, 2020

@StringEpsilon Thank you for the answer!

My goal is to trigger a new route in the child iframe react app without page refresh.
When I click on links inside this iframe, React router works as expected: page isn't refreshed, RR just replaces parts of react tree.

But when I try smth like iframeTag.contentWindow.location.href = 'new location' the iframe page is going to full refresh.
I thought this is how iframe works itself. To achieve my goal I decided to try smth else: an access of history object.

I did some clicks in the iframe app (RR did its thing). And then I did iframeTag.contentWindow.history.back() -- it worked! No full-page refresh, React Router did its thing: it changed only part of react tree.

Cool! I thought. I can trigger the iframe history from the parent window.

But my initial goal was not about back and forward. It was about setting a specific route for the child app.

So, how I can do that?

Imagine, I'm on the following url page/1. I tried to use iframe.contentWindow.history.pushState(null, null, 'page/2') but nothing happens: I'm still on page/1. (There is an issue that RR can't listen to pushState changes). So, I had to call iframe.contentWindow.history.go() (or go(0) to trigger it). Then page makes a full refresh to a page/2. So, basically the same stuff as location.href = 'page/2'.

I also tried this stuff without any iframes, to simplify the task: window.history.back() doesnt' trigger a full refresh, while window.history.go() or window.history.go(0) does.

So, there is my question, how to do this? How to change a route in an iframed app?
Thank you!

@StringEpsilon
Copy link

StringEpsilon commented Aug 5, 2020

History version 5 has support for custom window objects to enable easier use of iframes (see #624 ). I'm afraid you just have to wait for react-router version 6 to come out or risk the beta.

Also, I think you should probably seek advice on stackoverflow and or reactiflux on this. https://www.reactiflux.com/ This is clearly a support question and not a feature request or bug report.

@Carduelis
Copy link
Author

@StringEpsilon Thank you for sharing the 624, but it's not the case. The 624 PR is about desyncronization of history objects and about the ability to set such behavior.

Well, I believe it is a bug or at least a feature request. I was asking for an advise only after discovering an issue that works not as expected.

I will try to explain why I think this is a bug/feature request.

The whole thing is not about iframes. It's just when such behavior is crucial instead of optional.

  1. React Router in BrowserRouter component uses a history library, which is connected to native History API
  2. I expect I can access the history object via window.history and do some manipulation with it.
  3. I expect I can use window.history.back() and window.history.forward() to trigger React Router. And it works. RR replaces parts of the tree
  4. The same way I expect that I can set a specific route via window.history. There is a pushState method which can set url.
  5. I expect I can set new URL by calling window.history.pushState(null, null, 'the new URL') that should be accepted by React Router to trigger the route. But nothing happens.

Unfortunately, while delta in go([delta]) equals to 0, according History API is the same as location.reload() which causes full refresh. Therefore it could not be overrided by React Router.

From the other hand, if React Router works correctly when I call history.back() or history.go(<N>), I expect to set a specific route that will not cause the full refresh.

I think, that this is a bug or missing functionality.

@StringEpsilon
Copy link

Unfortunatly, there is no API to get notified about window.history.pushState() and window.history.replaceState(), as the browser will only fire onpopstate when the user navigates.

This library would need to monkeypatch the two functions to add in events or a callback.

@mjackson
Copy link
Member

It sounds like you want this library to be something it's not. This library isn't meant to replace the browser's built-in history API. It's just a thin layer the router uses to communicate with the browser. But users are still free to call the browser's built-in methods however they wish.

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

No branches or pull requests

3 participants