异步函数的 useState Hook 并发问题

M F*_*ied 5 reducers async-await reactjs react-hooks use-state

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

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

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

简而言之,修复:

如果您要从异步函数更新状态,则需要使用 reducer 来更新状态或使用 set state 的函数更新程序版本,因为函数更新程序获取最新更新版本的状态作为参数 (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();
Run Code Online (Sandbox Code Playgroud)

问题

发现在将 selecteContact 设置为 null 后,在 updateContact 完成等待 api 调用的承诺后,将其设置回所选联系人的旧值。

当我使用函数更新程序更新状态时,此问题已得到修复

setState(prevState => ({
       ...prevState,
       contacts: prevState.contacts.map(ct=> ct._id === updatedContact._id? updatedContact : ct)
    }));
Run Code Online (Sandbox Code Playgroud)

我还尝试使用 reducer 来测试给定这个问题的行为,发现即使您打算使用常规方式(没有函数更新程序)更新状态,reducer 也能正常工作。