Search code examples
javascriptreactjstimeoutautosave

Autosave to database after timeout


I want to perform autosave when a user fills out a form in a React component. The ajax call should be triggered when 3 seconds has passed since last onChange event.

My code below is inspired from an instructive article which shows how to accomplish this with setTimeout and clearTimeout. But I'm doing something wrong in my React implementation - the 3 sec delay isn't respected when typing.

Any ideas what's wrong here? Or is my thinking all together wrong about how to solve this?

class Form extends Component {
  constructor() {
    super();
    this.state = {
      isSaved: false
    };
    this.handleUserInput = this.handleUserInput.bind(this);
    this.saveToDatabase = this.saveToDatabase.bind(this);
  }
  saveToDatabase() {
    var timeoutId;
    this.setState({isSaved: false});
    if (timeoutId) {
        clearTimeout(timeoutId)
    };
    timeoutId = setTimeout( ()  => {
        // Make ajax call to save data.
        this.setState({isSaved: true});
    }, 3000);
  }
  handleUserInput(e) {
    const name = e.target.name;
    const value = e.target.value;
    this.setState({[name]: value});
    this.saveToDatabase();
  }
render() {
  return (
    <div>
      {this.state.isSaved ? 'Saved' : 'Not saved'}
      // My form.
    </div>
  )
}

Solution

  • Inside saveToDatabase method you are defining a new and undefined timeoutId variable every time the method is called. That's why the if statement never gets called.

    Instead, you need to scope out the variable and create a class data property in the constructor.

     constructor() {
       super();
       this.state = {
         isSaved: false
       };
       this.timeoutId = null;
       this.handleUserInput = this.handleUserInput.bind(this);
       this.saveToDatabase = this.saveToDatabase.bind(this);
     } 
    
     saveToDatabase() {
       this.setState({isSaved: false});
       if (this.timeoutId) {
         clearTimeout(this.timeoutId)
       };
       this.timeoutId = setTimeout( ()  => {
         // Make ajax call to save data.
         this.setState({isSaved: true});
       }, 3000);
     }