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)
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');
};
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');
});
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With