反应 setState 回调没有更新状态
react setState callback doesn't have the updated state
if monthOffset = 12
如果 yearOffset = 2018
,条件将评估为 true 并将 yearOffset
状态更新为 2017。根据我读过的反应文档和其他答案,this.setState
中的回调函数在状态更新后触发,但 console.log()
仍在输出 2018。我尝试了几种不同的方法根据其他相关问题的答案实施此代码,但我的不起作用。我不知道为什么。
handleClick(e) {
const { monthOffset, yearOffset } = this.state
this.setState({ monthOffset: monthOffset - 1 })
if ( monthOffset - 1 === 11 ) { this.setState((prevState) => {
return { yearOffset: prevState.yearOffset - 1 } },
() => {console.log("yearOffset", yearOffset)}
)}
console.log("clicked")
}
也许您可以通过以下方式简化您的逻辑,以避免多次调用 setState
可能导致意外结果:
handleClick(e) {
const { monthOffset, yearOffset } = this.state
// call setState once
this.setState({
// Always decrement month offset
monthOffset : monthOffset - 1,
// Only decrement year offset if current month offset === 12
yearOffset : (monthOffset === 12) ? yearOffset - 1 : yearOffset
}, () => {
console.log("state updated to", this.state)
})
console.log("clicked")
}
文档说回调总是有效,但我从经验中知道它并不总是 return 您所期望的。我认为这与在状态本身内部使用可变对象有关。
文档:https://reactjs.org/docs/react-component.html#setstate
不能完全依赖回调。相反,您可以做的是创建
var stateObject = this.state
对对象进行任何必要的更改:
stateObject.monthOffset -= 1
然后像这样设置状态:
this.setState(stateObject);
这样你就可以在 stateObject
中获得 nextState
的副本
澄清一下:您想在设置状态之前进行所有评估,所以这样做:
monthOffset -= 1
然后 if (monthOffset === 12) yearOffset -=1;
然后 var stateObj = {monthOffset: monthOffset, yearOffset: yearOffset}
然后 this.setState(stateObj);
From the documentation: "The second parameter to setState()
is an optional callback function that will be executed once setState is completed and the component is re-rendered. Generally we recommend using componentDidUpdate() for such logic instead."
所以基本上,如果您想获得下一个状态,您应该在调用 setState()
的函数中拥有它的副本,或者您应该从 componentDidUpdate
获得 nextState
事后思考: 您作为参数传递给 setState()
的任何内容都是 通过引用传递的 (而不是通过值)。所以,如果你在你的状态中有一个对象 SearchFilters: {}
,在你对 setState()
的调用中,你有
setState({SearchFilters: DEFAULT_SEARCH_FILTERS}); // do not do this
您可能已将 SearchFilters
设置为 DEFAULT_SEARCH_FILTERS
以清除名为 "Search Filters" 的表格,但实际上您实际上设置了 DEFAULT_SEARCH_FILTERS
(一个常量) 到 SearchFilters
,清除你的 DEFAULT_SEARCH_FILTERS
.
Expected behavior? You tell me.
在 React 中调用 setState
有两种流行的模式:对象 setState
和 "functional setState
". (or "previous state", or whatever you want to call the old state) 这样做是因为 setState
是异步的,因此后续setStates
有时可以 运行 在 React 设法完成第一个 setState
周期之前。
您在 setState
调用中使用了现有状态,因此它是使用函数式 setState
的合适位置。替换
this.setState({ monthOffset: monthOffset - 1 })
和
this.setState(monthOffset => {return {monthOffset: monthOffset - 1}})
如果你和我一样,当我第一次看到这个时,你可能会想,"Huh? How is that any different than what I have?" 不同之处在于,当 setState
被传递一个函数而不是一个对象时,它会将更新排队通过通常的解决过程,确保事情按顺序完成。
或者您可能没有想到这一点;您实际上在第二个 setState
调用中使用了功能 setState
。在你的第一个中使用它也将确保事情正确排队。
if monthOffset = 12
如果 yearOffset = 2018
,条件将评估为 true 并将 yearOffset
状态更新为 2017。根据我读过的反应文档和其他答案,this.setState
中的回调函数在状态更新后触发,但 console.log()
仍在输出 2018。我尝试了几种不同的方法根据其他相关问题的答案实施此代码,但我的不起作用。我不知道为什么。
handleClick(e) {
const { monthOffset, yearOffset } = this.state
this.setState({ monthOffset: monthOffset - 1 })
if ( monthOffset - 1 === 11 ) { this.setState((prevState) => {
return { yearOffset: prevState.yearOffset - 1 } },
() => {console.log("yearOffset", yearOffset)}
)}
console.log("clicked")
}
也许您可以通过以下方式简化您的逻辑,以避免多次调用 setState
可能导致意外结果:
handleClick(e) {
const { monthOffset, yearOffset } = this.state
// call setState once
this.setState({
// Always decrement month offset
monthOffset : monthOffset - 1,
// Only decrement year offset if current month offset === 12
yearOffset : (monthOffset === 12) ? yearOffset - 1 : yearOffset
}, () => {
console.log("state updated to", this.state)
})
console.log("clicked")
}
文档说回调总是有效,但我从经验中知道它并不总是 return 您所期望的。我认为这与在状态本身内部使用可变对象有关。
文档:https://reactjs.org/docs/react-component.html#setstate
不能完全依赖回调。相反,您可以做的是创建
var stateObject = this.state
对对象进行任何必要的更改:
stateObject.monthOffset -= 1
然后像这样设置状态:
this.setState(stateObject);
这样你就可以在 stateObject
nextState
的副本
澄清一下:您想在设置状态之前进行所有评估,所以这样做:
monthOffset -= 1
然后 if (monthOffset === 12) yearOffset -=1;
然后 var stateObj = {monthOffset: monthOffset, yearOffset: yearOffset}
然后 this.setState(stateObj);
From the documentation: "The second parameter to
setState()
is an optional callback function that will be executed once setState is completed and the component is re-rendered. Generally we recommend using componentDidUpdate() for such logic instead."
所以基本上,如果您想获得下一个状态,您应该在调用 setState()
的函数中拥有它的副本,或者您应该从 componentDidUpdate
获得 nextState
事后思考: 您作为参数传递给 setState()
的任何内容都是 通过引用传递的 (而不是通过值)。所以,如果你在你的状态中有一个对象 SearchFilters: {}
,在你对 setState()
的调用中,你有
setState({SearchFilters: DEFAULT_SEARCH_FILTERS}); // do not do this
您可能已将 SearchFilters
设置为 DEFAULT_SEARCH_FILTERS
以清除名为 "Search Filters" 的表格,但实际上您实际上设置了 DEFAULT_SEARCH_FILTERS
(一个常量) 到 SearchFilters
,清除你的 DEFAULT_SEARCH_FILTERS
.
Expected behavior? You tell me.
在 React 中调用 setState
有两种流行的模式:对象 setState
和 "functional setState
". setState
是异步的,因此后续setStates
有时可以 运行 在 React 设法完成第一个 setState
周期之前。
您在 setState
调用中使用了现有状态,因此它是使用函数式 setState
的合适位置。替换
this.setState({ monthOffset: monthOffset - 1 })
和
this.setState(monthOffset => {return {monthOffset: monthOffset - 1}})
如果你和我一样,当我第一次看到这个时,你可能会想,"Huh? How is that any different than what I have?" 不同之处在于,当 setState
被传递一个函数而不是一个对象时,它会将更新排队通过通常的解决过程,确保事情按顺序完成。
或者您可能没有想到这一点;您实际上在第二个 setState
调用中使用了功能 setState
。在你的第一个中使用它也将确保事情正确排队。