Pratish Shrestha
Pratish Shrestha

Reputation: 1902

How do I clear location.state in react-router on page reload?

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

Answers (10)

frodo2975
frodo2975

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

Jason G
Jason G

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

akrem bc
akrem bc

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

nezort11
nezort11

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

Badmaash
Badmaash

Reputation: 795

history.replace({ state: {} }). If you also want to redirect user somewhere then use history.replace({ pathname: '/profile/me', state: {} })

Upvotes: 3

jarora
jarora

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

Alex Freshmann
Alex Freshmann

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

Palash Gupta
Palash Gupta

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

Chris Gong
Chris Gong

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

Cam Song
Cam Song

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

Related Questions