Reactjs 异步函数的useState钩子并发问题

Reactjs 异步函数的useState钩子并发问题,reactjs,async-await,react-hooks,reducers,use-state,Reactjs,Async Await,React Hooks,Reducers,Use State,这是我面临、调查和解决的一个问题,我想与您分享我的经验 我发现,当您在异步函数中使用useState钩子维护状态,然后使用样式setState({…state,updatedProperty:updatedValue})更新状态时,可能会遇到一些并发问题 在某些情况下,这可能会导致应用程序丢失一些数据,因为异步函数保留状态的隔离版本,并且可能会覆盖存储在状态中的其他组件的数据 简而言之就是修复: 如果要从异步函数更新状态,因为函数更新程序获取状态的最新更新版本作为参数(prevState),则需

这是我面临、调查和解决的一个问题,我想与您分享我的经验

我发现,当您在异步函数中使用useState钩子维护状态,然后使用样式
setState({…state,updatedProperty:updatedValue})
更新状态时,可能会遇到一些并发问题

在某些情况下,这可能会导致应用程序丢失一些数据,因为异步函数保留状态的隔离版本,并且可能会覆盖存储在状态中的其他组件的数据

简而言之就是修复:

如果要从异步函数更新状态,因为函数更新程序获取状态的最新更新版本作为参数(prevState),则需要使用减速机更新状态或使用set state的函数更新程序版本
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也可以正常工作更新状态。

非常有趣。但是,您必须调用带有
prevState
的updatedContact作为参数?然后两个调用将传递相同的初始值
prevState
,这可能会失败?是的,这只是一个输入错误,这是复制和粘贴的问题。我修复了它。谢谢。