Prevent react-router history.push from reloading current route
My guess is that your component re-renders because something in your prop
changes when you make a router push. I suspect it might be the action
or key
properties of prop.location
. You could always check all the values of prop
during each render to see what changes.
You can solve this issue by comparing your old route path with the new one in the shouldComponentUpdate
life-cycle method. If it hasn't changed you are on the same route, and you can prevent the re-rendering by returning false
. In all other cases, return true
. By default this always returns true.
shouldComponentUpdate: function(nextProps, nextState) {
if(this.props.route.path == nextProps.route.path) return false;
return true;
}
You'll have to make further checks as well as this will prevent your component from updating on state
updates within the component as well, but I guess this would be your starting point.
Read more about shouldComponentUpdate
on the official react docs page.
Use this as an opportunity to return false when you're certain that the transition to the new props and state will not require a component update.
React Router v5.2 - Blocking route change with createBrowserHistory and history.block
The router context's history
object also has a block function but it works a little differently. It takes a callback that consumes location
and action
arguments.
history.block((location, action) => {...});
Returning false
from the callback blocks the navigation transition, returning true
allows the transition to go through.
React.useEffect(() => {
const unblock = history.block((location, action) => {
if (checkBlockingCondition) {
return window.confirm("Navigate Back?");
}
return true;
});
return () => {
unblock();
};
}, []);
Alternatively, react-router-dom suggests using the Prompt
component to conditionally block route transitions. Your code is very close to their preventing transitions example.
Updates to your last codesandbox:
- Use blocking state versus react ref so the prompt rerenders and reevaluates the condition.
- Render a
Prompt
component. - Prevent the default form submit action, i.e. to prevent the page from reloading.
code
import {
BrowserRouter as Router,
Prompt, // <-- import Prompt
Redirect,
Switch,
Route,
useLocation
} from "react-router-dom";
const Step1 = ({ id, history }) => {
const [isBlocking, setIsBlocking] = useState(false);
return (
<form
id={id}
onSubmit={(e) => {
e.preventDefault(); // <-- prevent default form action, i.e. page reload
history.push("/step2");
}}
>
<label>
Block navigation
<input
type="checkbox"
onChange={(e) => setIsBlocking(e.target.checked)}
/>
</label>
<br />
<br />
<button type="submit">Next</button>
<Prompt
when={isBlocking} // <-- blocking condition
message="Are you sure you want to leave?"
/>
</form>
);
};
React-router: is there a way to use push from history to append a query string after this current path?
You can get the current pathname
from the location
object of the current route being matched and rendered.
Example:
const location = useRouteMatch();
const queryString = "date=2022-02-15";
...
// as a string
history.push(`${location.pathname}?${queryString}`);
// or as an object
history.push({
pathname: location.pathname,
search: `?${queryString}`,
});
Related Topics
How to Download File in React Js
How to Convert Jquery Code to JavaScript
How to Get Full Path of Selected File on Change of <Input Type='File'> Using Javascript, Jquery-Ajax
How to Check If Input Field Is in Focus or Not
How to Delete a Localstorage Item When the Browser Window/Tab Is Closed
Why Does My Function Return Undefined Whilst I Do Give It an Argument
Convert Image from Url to Base64
Bootstrap Slides Lagging While Using Multi Item Carousel Using Angular 6
How to Get Only 1St Element of Json Data
How to Use Js to Open an HTML Select to Show Its Option List
Creating a Json Dynamically With Each Input Value Using Jquery
How to Manipulate a Select Options Based on Another Select Option in HTML
How to Hide Select Options With Javascript (Cross Browser)
Vuejs Reload If in the Same Route
How to Apply CSS to Parent Using Child Selector - With CSS or Angular 2
How to Merge an Array of Objects With Same Keys in Es6 JavaScript