Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Router - History fires first rather waiting

I got a issue here with methods firing not in the correct order. I can't figure out how to make the this.props.history.pushState(null, '/authors'); wait in the saveAuthor() method.

Help will be greatly appreciated.

import React, { Component } from 'react';
import AuthorForm from './authorForm';
import { History } from 'react-router';

const source = 'http://localhost:3000/authors';


// History Mixin Component Hack
function connectHistory (Component) {
  return React.createClass({
    mixins: [ History ],
    render () {
      return <Component {...this.props} history={this.history}/>
    }
  })
}


// Main Component
class ManageAuthorPage extends Component {
  state = {
    author: { id: '', firstName: '', lastName: '' }
  };

  setAuthorState(event) {
    let field = event.target.name;
    let value = event.target.value;
    this.state.author[field] = value;
    return this.setState({author: this.state.author});
  };

  generateId(author) {
    return `${author.firstName.toLowerCase()}-${author.lastName.toLowerCase()}`
  };

// Main call to the API

  postAuthor() {
    fetch(source, {
        method: 'post',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
        body: JSON.stringify({
            id: this.generateId(this.state.author),
            firstName: this.state.author.firstName,
        lastName: this.state.author.lastName
        })
    });
  };

  // Calling Save author method but the this.props.history goes first rather than this.postAuthor();

  saveAuthor(event) {
    event.preventDefault();
    this.postAuthor();
    this.props.history.pushState(null, '/authors');
  };

  render() {
    return (
      <AuthorForm
        author={this.state.author}
        onChange={this.setAuthorState.bind(this)}
        onSave={this.saveAuthor.bind(this)}
      />
    );
  }
}



export default connectHistory(ManageAuthorPage)
like image 705
Khpalwalk Avatar asked Oct 19 '22 16:10

Khpalwalk


2 Answers

Fetch is an asynchronous function. Execution continues to the next line before the request is finished. You need to queue code to run after the request finishes. The best way to do that would be to make your postAuthor method return the promise, and then use the promise's .then method in the caller.

class ManageAuthorPage extends Component {
// ...
  postAuthor() {
    return fetch(source, {
        method: 'post',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
        body: JSON.stringify({
            id: this.generateId(this.state.author),
            firstName: this.state.author.firstName,
        lastName: this.state.author.lastName
        })
    });
  };

  saveAuthor(event) {
    event.preventDefault();
    this.postAuthor().then(() => {
      this.props.history.pushState(null, '/authors');
    });
  };
// ...
}

If you're using a transpiler that supports ES7 async functions, then you could even do this in your saveAuthor method, which is equivalent and easier to read:

  async saveAuthor(event) {
    event.preventDefault();
    await this.postAuthor();
    this.props.history.pushState(null, '/authors');
  };
like image 106
Macil Avatar answered Oct 21 '22 05:10

Macil


So this is because your postAuthor method has an asynchronous call to fetch() inside of it. This is a time where you would want to pass in a function as a callback to the function, and then invoke that function inside the "completion" callback of the fetch call. The code would look something like this:

postAuthor(callback) {
  fetch(source, {
    /* Methods, headers, etc. */
  }, () => {
    /* Invoking the callback function that you passed */
    callback();
  });
);

saveAuthor(event) {
  event.preventDefault(); 
  /* Pass in a function to be invoked from within postAuthor when it is complete */
  this.postAuthor(() => {
    this.props.history.pushState(null, '/authors');
  });
};
like image 25
garrettmaring Avatar answered Oct 21 '22 05:10

garrettmaring