React Router - History Triggered First

Hey guys, here's the problem with methods shooting in the wrong order. I can't figure out how to do this.props.history.pushState(null, '/authors'); wait in the saveAuthor () method.

Help would 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) 
+5
source share
2 answers

Fetch is an asynchronous function. Execution continues to the next line until the request completes. You need to queue the code to run after the request is complete. The best way to do this is to force your postAuthor method to return the promise, and then use the promise method. Then 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 use a transpiler that supports async ES7 functions, you can 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'); }; 
+2
source

So this is because your postAuthor method has an asynchronous call to fetch() inside it. This is the time when you would like to pass a function as a function callback, and then call that function inside the "end" fetch callback. The code will 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'); }); }; 
+1
source

Source: https://habr.com/ru/post/1242675/


All Articles