Reputation: 1902
I am currently passing my state on route change like below:
<Link to={{
pathname:`/transactions/${props.transaction.id}`,
state: {transaction: props.transaction}
}}> View Details </Link>
My logic is that if "location.state.transaction" exists, don't fetch new data, else, fetch data.
Now the flaw is when there is a page reload. The application needs to fetch new data if the user reloads the page. I thought "location.state" would get cleared if there is a reload, but apparently the state is saved in sessionStorage.
How do I work around this? I could just fetch new data every time, but it should not fetch data when the 'View Details' Link is clicked.
Upvotes: 84
Views: 116958
Reputation: 11745
If you're using react hooks, you can use window.history
directly to clear the state without triggering a rerender. This is better than using the useHistory
hook's replace
method, which would cause your component to rerender.
window.history.replaceState({}, '')
Upvotes: 107
Reputation: 2733
None of these would reset my state using useNavigate. What I had to do was set up a useEffect on navigate.
...
const navigate = useNavigate()
...
useEffect(() => {
// set state here
....
},[navigate]
Upvotes: -1
Reputation: 151
In react Router V6 you can use useNavigate() to clear state for current path:
import React, { useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
useEffect(() => {
const location = useLocation();
const navigate = useNavigate();
navigate(location.pathname, {});
// reload and pass empty object to clear state
// we can also use replace option: ..., {replace: true}
}, []);
Upvotes: 14
Reputation: 635
In React Router v6 you can do:
const location = useLocation();
const navigate = useNavigate();
const state = location.state;
// Do some stuff with the state
// ...
// Clear the state after
navigate(location.pathname, { replace: true });
Navigating to current page won't do any visible effect other than clearing the state (modifing history).
Upvotes: 3
Reputation: 795
history.replace({ state: {} })
.
If you also want to redirect user somewhere then use history.replace({ pathname: '/profile/me', state: {} })
Upvotes: 3
Reputation: 5762
This is what might work.
const history = useHistory();
// consume the history.location.state and reset the state
useEffect(() => {
history.replace(`/transactions/${history.location.state.transaction.id}`, {});
}, []);
Upvotes: 1
Reputation: 481
I would suggest not to use the location
prop here, but to create a Route (wherever you define them) with a path: /transactions/:transactionId
, and to catch the transactionId
in the prop props.match.params.transactionId
inside of the target component. Then in the componentDidMount
you can dispatch the API request action in order to fetch the transaction. Don't forget to delete the state
param from the props of the Link.
Upvotes: 0
Reputation: 390
There is better approach without using the 3 party library.
We can use history.replace()
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/history.md
componentDidMount(){
const {location,history} = this.props;
//use the state via location.state
//and replace the state via
history.replace()
}
Upvotes: 23
Reputation: 8229
I also ran into this problem, and what I ended up doing was retrieving the browser history from react router and clearing specific location.state properties. So in your case, it would be transaction
. I did this in componentDidMount
so that after the first time you go to the page, that property should no longer be there,
import createHistory from 'history/createBrowserHistory'
...
componentDidMount(){
const history = createHistory();
if (history.location.state && history.location.state.transaction) {
let state = { ...history.location.state };
delete state.transaction;
history.replace({ ...history.location, state });
}
}
Upvotes: 25
Reputation: 2954
After you used the state, dispatch an action with an empty state again to clean the state.
this.props.dispatch(replace({
...this.props.location,
state: undefined
});
Upvotes: 5