1

So I have a sidenav that has expansion panels that open. I'm setting the state on which expansion panel is open. But on click of one of the sidenav, I get redirected to the list item path and the sidenav returns to original state. on the redirect I'd like for the part of the sidenav that was open to persist. I'm trying to do it like this. I'm not sure why it's not working.

 handleOpen = path => {
    this.setState({ openPath: path });
    sessionStorage.setItem('path', this.state.openPath);
  };

class Sidebar extends React.Component {
  constructor(props){
    super(props);
    let getPath = JSON.parse(sessionStorage.getItem('path'))
  this.state = {
    openPath: getPath
  };

  }
kyun
  • 9,710
  • 9
  • 31
  • 66
AnneJoday
  • 99
  • 2
  • 10
  • Provide an initial value to `getPath` and `setState` calls are asynchronous. Try putting `sessionStorage.setItem('path', this.state.openPath);` in the callback of `setState`. – Hassan Imam Nov 20 '18 at 02:16
  • have you considered using react router? it can be integrated into redux (or just your app state if not using redux) and it will take care of which route you're on and persist that data internally so you don't have to – Abdul Ahmad Nov 20 '18 at 02:17
  • @HassanImam hi sorry, I didn't quite understand that. Could you give me an example? – AnneJoday Nov 20 '18 at 02:17
  • @duxfox-- yes, the problem is I am using Gatsby which is a static site generator using react router under the hood. So I'm not able to configure my own routes, it kind of does that on its own based on its own createPages API. – AnneJoday Nov 20 '18 at 02:18
  • Update your `handleOpen` to `this.setState({openPath: path}, () => sessionStorage.setItem('path', this.state.openPath));` – Hassan Imam Nov 20 '18 at 02:21
  • I mean, to that effect you don't really have to even handle setting the session in the setState callback, you already have path coming in to the function. You could just do sessionStorage.setItem('path', path) and then handle setState after. – Keith Brewster Nov 20 '18 at 02:24
  • @HassanImam thank you. But I'm still not able to persist the open state of the nav. On the redirect it collapses the panel that was open and refreshes to the original state of the sidenav. How can I persist this with session/local storage. Am I doing something wrong in my code? Does it need to be in a componentDidMount. – AnneJoday Nov 20 '18 at 02:24
  • What's your sidebar component look like? – Keith Brewster Nov 20 '18 at 02:25
  • Have you provided the initial value to your `getPath`? `let getPath = JSON.parse(sessionStorage.getItem('path')) || 'give your initial value here'` – Hassan Imam Nov 20 '18 at 02:26
  • @HassanImam Sorry, for asking so much. I'm just trying to understand this error Unexpected token V in JSON at position 0. So obviously my getitem from session storage is undefined on a refresh. Since it doesn't exist. Is there a way around this? – AnneJoday Nov 20 '18 at 02:36
  • Yes, when in the constructor, when you are accessing the `path`, on the first load, its value is not available, so you have to provide that value. So, first set the `path` value in the `sessionStorage`. – Hassan Imam Nov 20 '18 at 02:38
  • @HassanImam ok last question. I was under the impression that session storage clears on a refresh. However, my refresh doesn't refresh the state of the sidenav. It just keeps that panel opened. is there a way to make sure a refresh happens on page reload. I only want it to store sessionStorage for a redirect on click of a list item on the sidenav. A page fresh shouldn't keep parts of the panel open. I'm logging the state in a p tag to see what is open. the state and on refresh is the last opened panel. – AnneJoday Nov 20 '18 at 03:01
  • Session Storage value will persist for the entire session. You have to come up with logic to [check refresh of the page](https://stackoverflow.com/questions/50026028/react-how-to-detect-page-refresh-f5) and take action accordingly. – Hassan Imam Nov 20 '18 at 03:05

1 Answers1

4

You should probably show at least how the component is used but at first glance:

sessionStorage.setItem('path', this.state.openPath);

needs to be

sessionStorage.setItem('path', JSON.stringify(this.state.openPath));

also I'd reverse these lines:

  handleOpen = path => {
    this.setState({ openPath: path });
    sessionStorage.setItem('path', this.state.openPath);
  };

to

  handleOpen = path => {
    sessionStorage.setItem('path', this.state.openPath);
    this.setState({ openPath: path });
  };

It shouldn't matter since Javascript is single threaded but at least stylistically I like to make setState the last expression in any handlers.

bknights
  • 14,408
  • 2
  • 18
  • 31