Prevent React-Router History.Push from Reloading Current Route

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:

  1. Use blocking state versus react ref so the prompt rerenders and reevaluates the condition.
  2. Render a Prompt component.
  3. 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>
);
};

Edit react-router-v5-2-blocking-route-change-with-createbrowserhistory-and-history

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



Leave a reply



Submit