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.