这是我面临,研究和解决的问题,并希望与您分享我的经验。
我发现,当您使用useState HOOK维护状态,然后在异步函数中使用样式setState({...state, updatedProperty: updatedValue})
更新状态时,您可能会遇到一些并发问题。
在某些情况下,这可能导致应用程序丢失一些数据,原因是异步功能保持状态的隔离版本,并且可能会覆盖状态中存储的某些其他组件的数据。
简而言之:
如果要通过异步函数更新状态,则需要使用化简器更新状态或使用set状态的函数更新程序版本,因为函数更新程序会获取状态的最新更新版本( prevState)
setState(prevState => ({...prevState, updatedProperty: updatedValue});
详细说明:
我正在开发数据上下文,以管理保存在数据库上的用户联系人,该数据库托管在云MongoDB集群上,并由后端Web服务进行管理。
在上下文提供程序中,我使用了useState挂钩来维护状态,并按如下所示对其进行更新
const [state, setState] = useState({
contacts: [],
selectedContact: null
});
const setSelected = (contact) => setState({...state, selectedContact: contact});
const clearSelected = ()=> setState({...state, selectedContact: null};
const updateContact = async(selectedContact) => {
const res = await [some api call to update the contact in the db];
const updatedContact = res.data;
// To check the value of the state inside this function, I added the following like and found
// selectedContact wasn't null although clearSelected was called directly after this function and
// selectedContact was set to null in Chrome's React dev tools state viewer
console.log('State Value: ' + JSON.stringify(state));
//The following call will set selectedContact back to the old value.
setState({
...state,
contacts: state.contacts.map(ct=> ct._id === updatedContact._id? updatedContact : ct)
});
}
//In the edit contact form submit event, I called previous functions in the following order.
updateContact();
clearSelected();
问题
发现在selecteContact设置为null之后,在updateContact完成等待api调用的诺言之后,将其设置回所选联系人的旧值。
当我使用功能更新程序更新状态时,此问题已解决
setState(prevState => ({
...prevState,
contacts: prevState.contacts.map(ct=> ct._id === updatedContact._id? updatedContact : ct)
}));
我还尝试使用reducer来测试给出此问题的行为,发现即使您要使用常规方式(不使用功能更新器)更新状态,reducer仍能正常工作。