React Router - Why is history.replace pushing instead of replacing? - javascript

I'm working on a react project where I created a component using <Promp/> from react-router to implement a confirm dialog that shows up when user attempts to leave the route without saving current changes:
The component works properly when I try to leave the current route, but I also want to display the dialog when user clicks a button meant to discard the changes intentionally. Since modal only displays based on a route change, a workaround that I could think of is to call history.push when button clicked:
const history = useHistory();
const { pathname } = useLocation();
const onCancel = () => {
history.push(pathname);
};
that it pushes the same route and this way changes are discarded and user stays on the same page as if nothing happens, but now the problem with this workaround is that user won't be able to go back to previous route because history stack is getting filled with the same location, so in order to solve this I tried to use history.replace which is meant to replace the top of the stack instead of pushing a new element, but it's not working this way and is acting like history.push adding new elements with the same location.
Is this bug or am I missing something? what could be a workaround for this?
Any suggestion is welcome.

Seems to me that you want to reload, i.e. re-render, the page. For that, you can use history.go(0).
Take a look at this: How do I reload a page with react-router?

Related

What is the best way to refresh a page?

I would like to know what is the best way to refresh the page after typing.
For example, I press a button that modifies the name of a product, how can I do that from the moment I validate my modification, the changes appear immediately, without having to manually refresh the browser page.
I saw some example with react-router, doing a redirect or using 'history.push', I also saw with the 'window.location.reload (false)' but it doesn't feel right because you can 'see' that the page refresh (yes you don't manually refresh but ... maybe there is something better to do)
Well, the best way is to not refresh the page at all.
Specially if you are using React. Every piece of data that you display on your UI is supposed to be stored in some kind of state. Even if that data should somehow be validated asynchronously (I think this is your case), once done, you should trigger a state change that will cause the interested components to re-render and display the new information.
You can use useState hooks of react to view the changes without refreshing the window.
In every state change, which means the change of value on the given state, react automagically rerender to show the latest data.
const [productName, setProductName] = useState('');
cosnt handleButtonClick = (name) => setProductName(name)
return (
<>
Production Name: {productName} // Product name changes on every button click.
<button onClick={() => handlebuttonClick(dynamicallySendRequiredDataFromHere)}> Change product name </button>
<>
)
It all depends on your requirement actually.
If you want to reload the page to get something which can only be achieved by reloading then use
window.location.reload()
If you want to reload just to get the data then make the API call and connect your component with the state that gets the value after the API call
If you want to maintain the history stack the use
history.push()
If you dont want to maintain the history stack the use
history.replace()
Some fancy times when you want to set cookie or storage to your page but dont want to refresh current page you can use window.open with the origin and target
window.open(window.location.origin, '_blank')

React Router history.push is updated when I scroll through images inside the component, but the route doesn't actually change

I have a component that scrolls through images on click. When I click the back button that implements history.goBack() it should take me back to the main page, however it cycles back through the images and I have to click multiple times to actually get back. I thought this was due to using store and the component updating and causing history.push to push the current location onto to the stack and then causing me to have to cycle back through the stack, but after removing store the problem still persists. Is there a way to keep react router history from updating if the pathname doesn't change?
You can do this by a simple condition checking before you execute your history.push('/path') command.
if (history.location.pathname !== '/path_you_are_about_to_push') {
history.push('/path_you_are_about_to_push');
}
It will prevent unnecessary piling up of route history. history.location.pathname is a string of your current route path. You can go here to study more about history properties and methods.

How to prevent browser back with react-router-dom and keep state

I'm developing with react-router-dom. Now, I'm creating a page where users can enter information in a form. What I want to do is prevent the user from losing the information they enter if they accidentally return to the previous page.
I first found a way to stop the browser back in the article below. It seems that the moment you return to the previous page, you immediately return to the original page, effectively preventing you from returning to the previous page.
React.useEffect (() => {
return () => {
props.history.goForward ();
}
}, []);
React Router Dom v4 handle browser back button
However, in this case, the previous page will be returned once, so all the current page information (state) will be reset. Is there a solution to prevent the state from resetting?
Or is there a smarter way to solve this?
Below, I have prepared an image for explanation.
You have several ways to approach your answer, but all of them have 1 concept, and that is Higher-order-component, so in this case, you have to have a top-level component (Higher than react-router), so when the location has changed, you don't lose the information in the state. in another word, you have to have a general state.
So how you can reach this goal? you have several ways and I'm here to help you use them.
redux - https://redux.js.org/.
context - https://reactjs.org/docs/context.html.
react state - https://reactjs.org/docs/higher-order-components.html.
localStorage or sessionStorage - https://www.robinwieruch.de/local-storage-react.
...
these are just some examples of what you can do to prevent losing state when the browser location has changed.

Calling React Router from vanilla JS

I have a react single page application using React Router, and having paths defined using Link as shown below:
<Link to="second" className="level-2" params={{id:item.content}} title={item.name}>{item.name}<br/></Link>
This changes url from /myapp/firsturi to /myapp/seconduri
Is it possible for me to make the same react router action using vanilla JS? I tried using history.pushState() and history.replaceState() but while the url updates correctly, the content on the page does not. I can get the same thing using window.location.href="/myapp/seconduri" but that causes a page refresh which is not what I want.
Any idea how to go about this?
React Router relies on the history module to handle locations. When the page loads it parses the initial URL, which is why setting window.location.href works.
The history that you use includes a listen function which React Router uses to listen for location changes. When one occurs, it will trigger a re-matching of the new location against your routes, which in turn will render the correct components.
Manually calling pushState/replaceState does not trigger the listening function, which is why your app is failing to update. Instead, you should use your history instance to navigate.
This has worked for me:
// simulate navigation to where you want to be (changes URL but doesn't navigate)
window.history.pushState("","","/url");
// simulate navigation again so that
window.history.pushState("","","/url");
// when you simulate back, the router tries to get BACK to "/url"
window.history.go(-1);
Everything else I tried was just forcing the DOM to reload again as if it was a link click.

Iron Router hook on a route before actually changing the template

i am trying to show the user a payment popup as soon as he clicks on a payed object.
But after he pays he should directly enter the content he clicked on.
Therefore i think its a good solution to solve this with the router, because i want every link on the page that redirects to this content to show this popup.
My problem is i want to show the popup before redirecting the user.
So i tryed the onBeforeAction hook and stuff but everything working with the iron router seems to only hook in after the URL of the browser changed and the current template was unloaded.
Do you have an idea how to get this kind of behavior?
Cheers
Based on this answer, here is how you can hook the router using Router.onStop():
// onStop hook is executed whenever we LEAVE a route
Router.onStop(function(){
//check if the current route is the page from where you need to show your
//popup and show it based on, for instance, a session variable containing
//the previously clicked content id.
});
It's a common use case that I don't think is directly achievable within the iron router framework at present (although I would be delighted to be corrected!). As you've discovered, onBeforeAction is run before the page has rendered but after the new route has been run, so the old page has already disappeared.
Effectively, you're looking to queue the running of a new route until a certain action has been completed. The use case for which I've experienced this requirement is page transitions, for which the best solution appears to be to do completely the opposite of what you propose: i.e. to add the logic to an event attached to the link, and only redirect to the new route once that logic has been satisfactorily completed (i.e. the popup has been closed in your case).
I agree that doing something in the router would be a sensible way to approach this, but I'm not sure it's possible in iron router as things stand. Note that this has already been raised though!
Will this workshop?
'unload - runs just once when you leave the route for a new route.'
From
https://github.com/EventedMind/iron-router/blob/devel/DOCS.md#unload-hook

Categories

Resources