Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to recover state on back button with react

If I have a simple react component that records a click count for a button and on each click records a new history state without changing the URL. When the user clicks back how do I restore the state to as it was?

I can do as it is here using the native JavaScript history object, but it fails when the user transitions back to the first state and back from a different component into the last state of this one.

I suspect that there is a better to do this using react-router (1.0)?

import React, { Component } from 'react';

export default class Foo extends Component {
  state = {
    clickCount: 0,
  };

  componentWillMount() {
    window.onpopstate = (event) => {
      if (event.state.clickCount) {
        this.setState({ clickCount: event.state.clickCount });
      }
    };
  }

  onClick() {
    const newClickCount = this.state.clickCount + 1;
    const newState = { clickCount: newClickCount };
    this.setState(newState);
    history.pushState(newState, '');
  }

  render() {

    return (
      <div>
        <button onClick={this.onClick.bind(this)}>Click me</button>
        <div>Clicked {this.state.clickCount} times</div>
      </div>
    );
  }
}
like image 511
SystemicPlural Avatar asked Feb 12 '16 16:02

SystemicPlural


1 Answers

localStorage or even cookies are options, but probably not the best way. You should store the count in a database, this way you can set the initial state in your constructor to the last value saved in the database.

Another option, if you only need to persist the count on the client-side(and not in a database) is using a closure.

// CountStore.js
var CountStore = (function() {
  var count = 0;

  var incrementCount = function() {
    count += 1;
    return count;
  };

  var getCount = function() {
    return count;
  };

  return {
    incrementCount: incrementCount,
    getCount: getCount
  }

})();

export default CountStore;

So your code would change to the below.

import React, { Component } from 'react';
import CountStore from './CountStore'; 

export default class Foo extends Component {
  state = {
    clickCount: CountStore.getCount()
  };

  componentWillMount() {
    window.onpopstate = (event) => {
      if (event.state.clickCount) {
        this.setState({ clickCount: event.state.clickCount });
      }
    };
  }

  onClick() {
    const newClickCount = CountStore.incrementCount();
    const newState = { clickCount: newClickCount };
    this.setState(newState);
  }

  render() {

    return (
      <div>
        <button onClick={this.onClick.bind(this)}>Click me</button>
        <div>Clicked {this.state.clickCount} times</div>
      </div>
    );
  }
}

There may be a cleaner way of using react-router, but this is an option.

like image 114
grizzthedj Avatar answered Sep 22 '22 23:09

grizzthedj