What exactly do they mean? If I understand it correctly, I can't use this.state when calculating new state, unless I pass a function as a first parameter to setState():
// Wrong
this.setState({a: f(this.state)});
// Correct
this.setState(prevState => {return {a: f(prevState)}});
But I can use this.state to decide what to do:
if (this.state.a)
this.setState({b: 2});
What about props?
// Correct or wrong?
this.setState({name: f(this.props)});
And supposedly I can't expect this.state to change after calling this.setState:
this.setState({a: 1});
console.log(this.state.a); // not necessarily 1
Then, say I have a list of users. And a select where I can make one user current:
export default class App extends React.Component {
...
setCurrentUserOption(option) {
this.setState({currentUserOption: option});
if (option)
ls('currentUserOption', option);
else
ls.remove('currentUserOption');
}
handleAddUser(user) {
const nUsers = this.state.users.length;
this.setState(prevState => {
return {users: prevState.users.concat(user)};
}, () => {
// here we might expect any number of users
// but if first user was added, deleted and added again
// two callbacks will be called and setCurrentUserOption
// will eventually get passed a correct value
// make first user added current
if ( ! nUsers)
this.setCurrentUserOption(this.userToOption(user));
});
}
handleChangeUser(user) {
this.setState(prevState => {
return {users: prevState.users.map(u => u.id == user.id ? user : u)};
}, () => {
// again, we might expect any state here
// but a sequence of callback will do the right thing
// in the end
// update value if current user was changed
if (_.get(this.state, 'currentUserOption.value') == user.id)
this.setCurrentUserOption(this.userToOption(user));
});
}
handleDeleteUser(id) {
this.setState(prevState => {
return {users: _.reject(prevState.users, {id})};
}, () => {
// same here
// choose first user if current one was deleted
if (_.get(this.state, 'currentUserOption.value') == id)
this.setCurrentUserOption(this.userToOption(this.state.users[0]));
});
}
...
}
Do all callbacks are executed in sequence after batch of changes to state was applied?
On second thought, setCurrentUserOption is basically like setState. It enqueues changes to this.state. Even if callbacks get called in sequence, I can't rely on this.state being changed by previous callback, can I? So it might be best not to extract setCurrentUserOption method:
handleAddUser(user) {
const nUsers = this.state.users.length;
this.setState(prevState => {
let state = {users: prevState.users.concat(user)};
if ( ! nUsers) {
state['currentUserOption'] = this.userToOption(user);
this.saveCurrentUserOption(state['currentUserOption']);
}
return state;
});
}
saveCurrentUserOption(option) {
if (option)
ls('currentUserOption', option);
else
ls.remove('currentUserOption');
}
That way I get queuing of changes to currentUserOption for free.