我有一个在单击时被调用以更新状态的函数,但是仅在单击两次时才更新。例如,如果单击一次,它将复制先前的更新,并且仅当再次单击时,状态才会更新。
const select = day => {
let markedDay = day.dateString
setSelected([...selected, markedDay])
let obj = selected.reduce((c, v) => Object.assign(c, {[v]: { selected: true, disableTouchEvent: true }}), {})
setBooking(obj)
}
该函数的目的是:1)使用setSelected
钩子将数据收集到数组中,以及2)使用Object.assign
和reduce
将其转换为具有新分配属性的对象。
当函数被调用一次时,挂钩selected
中的状态setSelected
第一次显示为空或显示为先前状态。 obj
使用相同的模式。我希望函数在第一次调用时更新状态,而不必被调用两次。
更新
我已将函数简化为以下函数,但仍然存在相同的问题:
const select = day => {
let markedDay = day.dateString
setSelected({...selected, [markedDay]: { selected: true, disableTouchEvent: true }})
}
该功能适用于react-native-calendars,selected
的示例为:
"2019-11-18": Object {
"selected": true,
"disableTouchEvent": true,
}
每次选择一个日期时,我都想查看上述对象在状态上的更新,但是只有当我第二次单击它时,它才会更新。
答案 0 :(得分:1)
React中的设置状态是异步的,因此更新将不会反映到该状态,直到下一次渲染。代码的问题在于,设置状态后,您将立即使用状态的新值,但是更新后的值仅在下一个组件渲染时可用。要解决此问题,您可以在设置状态之前重用selected
的更新值:
const select = day => {
let markedDay = day.dateString
const newSelected = [...selected, markedDay];
let obj = newSelected.reduce((c, v) => Object.assign(c, {
[v]: {
selected: true,
disableTouchEvent: true
}
}), {})
setSelected(newSelected)
setBooking(obj);
}
或者,如果您想在setBooking
中使用更新后的状态值,则需要在跟踪useEffect
变量的同时在selected
内部进行该调用。
const select = day => {
let markedDay = day.dateString
setSelected([...selected, markedDay]);
}
useEffect(() => {
let obj = selected.reduce((c, v) => Object.assign(c, {
[v]: {
selected: true,
disableTouchEvent: true
}
}), {})
setBooking(obj);
}, [selected])
当您具有更复杂的状态时,这可能是更可取的方法。
答案 1 :(得分:0)
我只能冒险猜测正在发生的事情,但是我认为我们在这里看到的是race condition。我猜测setBooking或setSelected应该从您的状态中获取值并调整最终产品的呈现,是吗?
问题在于react中的设置状态是异步的。如果我说
console.log(this.state.foo) // 'bar'
this.setState({foo:'fizz'})
console.log(this.state.foo) // still 'bar'
react仍在后台设置状态;还没有完成,所以我得到了旧值。
有三种方法可以修复此错误。
方法1:使渲染语句依赖于依赖状态的状态/调用函数。这样,只要状态更新,您呈现的内容就会更新。
方法2:将要存储在状态中的参数作为参数传递给setBooking或setSelected函数。如果他们只是接收值,则无需担心种族状况。
方法3:可以将强制setState写入为同步状态。
this.setState({foo:'bar'},()=>{
//do something
}
)
此代码的“执行操作”部分直到设置了状态后才会执行。它有一点代码味道(毕竟,您没有利用asynch的优势),但是有时候,如果您想在componentDidMount中以及组件的生命周期中重用某个函数,则有必要。