React异步函数中dispatch更新后useSelector取值未更新如何解决?
问题根因
你在submitUpdatedBugs异步函数中获取的bugs变量,属于当前组件渲染周期闭包捕获的快照值。即便dispatch(updateBugs(newBug))成功更新了Redux store的状态,也只会触发组件重新渲染生成新的闭包,本次正在执行的submitUpdatedBugs函数内的bugs变量依旧是函数创建时的旧值,不会跟随store更新自动变化。
修复方案
这里提供3种常用的修复思路,可根据你的业务场景选择:
方案1:直接构造最新数据传参
你已经持有待更新的newBug数据,直接按照reducer中的更新逻辑构造出最新的bugs列表传入接口即可,无需依赖store返回的状态:
const submitUpdatedBugs = async () => { const newBug = { title: enteredTitle, details: enteredDetails, steps: enteredSteps, version: enteredVersion, priority: enteredPriority, assigned: enteredAssigned, creator: enteredCreator, id: enteredId, }; // 构造最新bugs列表,逻辑和updateBugs reducer中的更新规则保持一致 const updatedBugs = bugs.map(item => item.id === newBug.id ? newBug : item); await dispatch(updateBugs(newBug)); await sendUpdatedBugsToServer(updatedBugs); }
方案2:在Thunk中获取最新状态
如果不想在组件层处理数据构造逻辑,可以把更新+上报逻辑封装到Redux Thunk中,通过Thunk自带的getState方法直接获取最新的store状态:
// bug-actions.js 新增thunk方法 export const updateAndSaveBugs = (newBug) => { return async (dispatch, getState) => { // 先更新本地状态 dispatch(updateBugs(newBug)); // 直接获取最新的bugs状态 const latestBugs = getState().bugs.bugs; // 上报到服务器 const response = await fetch(`${databaseURL}/bugs.json`, { method: 'PUT', body: JSON.stringify(latestBugs), headers: { 'Content-Type': 'application/json' }, }); if (!response.ok) { throw new Error('cannot store new bug'); } } }
组件中直接调用该Thunk即可:
const submitUpdatedBugs = async () => { const newBug = { // 你的newBug属性 }; await dispatch(updateAndSaveBugs(newBug)); }
方案3:通过useEffect监听状态变更触发上报
如果需要严格等store更新完成后再执行上报,可以通过useEffect监听bugs的变化,变更后触发上报逻辑:
const EditBug = () => { const dispatch = useDispatch(); const { bugs } = useSelector((state) => state.bugs); // 标记是否需要执行上报 const [needSubmit, setNeedSubmit] = useState(false); const submitUpdatedBugs = async () => { const newBug = { // 你的newBug属性 }; await dispatch(updateBugs(newBug)); setNeedSubmit(true); } // bugs变更后触发上报 useEffect(() => { if (needSubmit) { sendUpdatedBugsToServer(bugs); setNeedSubmit(false); } }, [bugs, needSubmit]); }
额外代码优化提示
你现有的sendUpdatedBugsToServer方法中,调用异步函数storeData时没有加await,会导致try/catch无法捕获异步抛出的错误,建议修改为:
export const sendUpdatedBugsToServer = async (newBugsList) => { const storeData = async (newBugsList) => { const response = await fetch(`${databaseURL}/bugs.json`, { method: 'PUT', body: JSON.stringify(newBugsList), headers: { 'Content-Type': 'application/json' }, }); if (!response.ok) { throw new Error('cannot store new bug'); } }; try { await storeData(newBugsList); } catch (error) { console.error(error.message); } };
内容的提问来源于stack exchange,提问作者user16589580
相关产品推荐
相关产品推荐

