状态更新可能是异步的
State updates might be asynchronous
它们到底是什么意思?如果我理解 it 正确,我不能在计算新状态时使用 this.state
,除非我将函数作为第一个参数传递给 setState()
:
// Wrong
this.setState({a: f(this.state)});
// Correct
this.setState(prevState => {return {a: f(prevState)}});
但我可以使用this.state
来决定要做什么:
if (this.state.a)
this.setState({b: 2});
道具呢?
// Correct or wrong?
this.setState({name: f(this.props)});
据说我不能指望 this.state
在调用 this.setState
后会发生变化:
this.setState({a: 1});
console.log(this.state.a); // not necessarily 1
然后,假设我有一个用户列表。还有一个 select,我可以让一个用户成为当前用户:
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]));
});
}
...
}
是否在应用批量状态更改后按顺序执行所有回调?
转念一想,setCurrentUserOption
基本上和 setState
一样。它将对 this.state
的更改排入队列。即使按顺序调用回调,我也不能依赖 this.state
被先前的回调更改,可以吗?所以最好不要提取 setCurrentUserOption
方法:
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');
}
这样我就可以免费排队更改 currentUserOption
。
你并没有问一个非常具体的问题。 "What does this mean" 不是很继续下去。但是您通常似乎了解基础知识。
调用 setState()
有两种可能的方法:向它传递一个要合并到新状态的对象,或者向它传递一个函数,其中 returns 一个对象被合并到一种类似于第一种方式的时尚。
所以你要么这样做:
// Method #1
this.setState({foo: this.state.foo + 1}, this.someCallback);
或者这样:
// Method #2
this.setState((prevState) => {return {foo: prevState.foo + 1}}, this.someCallback);
主要区别在于,使用方法 #1,foo
将根据 您调用 setState()
[=70= 时的任何状态递增 1 ],而在方法 #2 中,foo
将根据 在箭头函数运行 时的前一个状态递增 1。因此,如果您有多个 setState()
调用发生在实际状态更新之前的 "same" 时间,使用方法 #1 它们可能会冲突 and/or 基于过时的状态,而使用方法 #2它们保证具有最新的状态,因为它们在状态更新阶段一个接一个地同步更新。
这是一个说明性的例子:
// Method #1
class App extends React.Component {
constructor(props) {
super(props);
this.state = {n: 0};
this.increment.bind(this);
}
componentDidMount() {
this.increment();
this.increment();
this.increment();
}
increment() {
this.setState({n: this.state.n + 1}, () => {console.log(this.state.n)});
}
render() {
return (
<h1>{this.state.n}</h1>
);
}
}
React.render(
<App />,
document.getElementById('react_example')
);
在上面:您会在控制台中看到:
> 1
> 1
> 1
this.state.n
的最终值为 1
。当 n
的值为 0
时,所有 setState()
调用都已排队,因此它们都只是将其设置为 0 + 1
.
// Method #2
class App extends React.Component {
constructor(props) {
super(props);
this.state = {n: 0};
this.increment.bind(this);
}
componentDidMount() {
this.increment();
this.increment();
this.increment();
}
increment() {
this.setState((prevState) => {return {n: prevState.n + 1}}, () => {console.log(this.state.n)});
}
render() {
return (
<h1>{this.state.n}</h1>
);
}
}
React.render(
<App />,
document.getElementById('react_example')
);
在上面,您会在控制台中看到:
> 3
> 3
> 3
n
的最终值为 3
。与方法 #1 一样,所有 setState()
调用同时排队。但是,由于它们使用一个函数来同步更新,以便使用最新状态 - 包括并发状态更新对状态所做的更改 - 它们正确地将 n
递增三倍,正如您所期望的那样。
现在,为什么 console.log()
对于方法 #2 显示了三次 3
,而不是 1
、2
、3
?答案是 setState()
回调在 React 的状态更新阶段结束时一起发生,而不是在特定状态更新发生后立即发生。所以在这方面方法#1 和#2 是相同的。
它们到底是什么意思?如果我理解 it 正确,我不能在计算新状态时使用 this.state
,除非我将函数作为第一个参数传递给 setState()
:
// Wrong
this.setState({a: f(this.state)});
// Correct
this.setState(prevState => {return {a: f(prevState)}});
但我可以使用this.state
来决定要做什么:
if (this.state.a)
this.setState({b: 2});
道具呢?
// Correct or wrong?
this.setState({name: f(this.props)});
据说我不能指望 this.state
在调用 this.setState
后会发生变化:
this.setState({a: 1});
console.log(this.state.a); // not necessarily 1
然后,假设我有一个用户列表。还有一个 select,我可以让一个用户成为当前用户:
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]));
});
}
...
}
是否在应用批量状态更改后按顺序执行所有回调?
转念一想,setCurrentUserOption
基本上和 setState
一样。它将对 this.state
的更改排入队列。即使按顺序调用回调,我也不能依赖 this.state
被先前的回调更改,可以吗?所以最好不要提取 setCurrentUserOption
方法:
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');
}
这样我就可以免费排队更改 currentUserOption
。
你并没有问一个非常具体的问题。 "What does this mean" 不是很继续下去。但是您通常似乎了解基础知识。
调用 setState()
有两种可能的方法:向它传递一个要合并到新状态的对象,或者向它传递一个函数,其中 returns 一个对象被合并到一种类似于第一种方式的时尚。
所以你要么这样做:
// Method #1
this.setState({foo: this.state.foo + 1}, this.someCallback);
或者这样:
// Method #2
this.setState((prevState) => {return {foo: prevState.foo + 1}}, this.someCallback);
主要区别在于,使用方法 #1,foo
将根据 您调用 setState()
[=70= 时的任何状态递增 1 ],而在方法 #2 中,foo
将根据 在箭头函数运行 时的前一个状态递增 1。因此,如果您有多个 setState()
调用发生在实际状态更新之前的 "same" 时间,使用方法 #1 它们可能会冲突 and/or 基于过时的状态,而使用方法 #2它们保证具有最新的状态,因为它们在状态更新阶段一个接一个地同步更新。
这是一个说明性的例子:
// Method #1
class App extends React.Component {
constructor(props) {
super(props);
this.state = {n: 0};
this.increment.bind(this);
}
componentDidMount() {
this.increment();
this.increment();
this.increment();
}
increment() {
this.setState({n: this.state.n + 1}, () => {console.log(this.state.n)});
}
render() {
return (
<h1>{this.state.n}</h1>
);
}
}
React.render(
<App />,
document.getElementById('react_example')
);
在上面:您会在控制台中看到:
> 1
> 1
> 1
this.state.n
的最终值为 1
。当 n
的值为 0
时,所有 setState()
调用都已排队,因此它们都只是将其设置为 0 + 1
.
// Method #2
class App extends React.Component {
constructor(props) {
super(props);
this.state = {n: 0};
this.increment.bind(this);
}
componentDidMount() {
this.increment();
this.increment();
this.increment();
}
increment() {
this.setState((prevState) => {return {n: prevState.n + 1}}, () => {console.log(this.state.n)});
}
render() {
return (
<h1>{this.state.n}</h1>
);
}
}
React.render(
<App />,
document.getElementById('react_example')
);
在上面,您会在控制台中看到:
> 3
> 3
> 3
n
的最终值为 3
。与方法 #1 一样,所有 setState()
调用同时排队。但是,由于它们使用一个函数来同步更新,以便使用最新状态 - 包括并发状态更新对状态所做的更改 - 它们正确地将 n
递增三倍,正如您所期望的那样。
现在,为什么 console.log()
对于方法 #2 显示了三次 3
,而不是 1
、2
、3
?答案是 setState()
回调在 React 的状态更新阶段结束时一起发生,而不是在特定状态更新发生后立即发生。所以在这方面方法#1 和#2 是相同的。