React.js中如何立即获取当前最新的state状态数据?
问题根因
React 函数组件的状态取值依赖渲染闭包,setState是异步批量执行的,调用setSortByKey不会同步修改当前执行上下文中的sortByKey变量,必须等组件重渲染完成后,新的闭包中才会拿到更新后的状态值。你在setSortByKey后立刻调用fetchItemsFilter,此时方法内读取的还是上一次渲染闭包里的旧状态值,自然拿不到最新选中的内容。
可用解决方案
方案1:直接传值调用(推荐用于当前场景)
不依赖闭包中的状态,直接把下拉框选中的值作为参数传入请求方法,从根源上避开状态异步更新的问题。
// 下拉框变更回调 const updateSortByKey = (e) => { const selectedValue = e.target.value; setSortByKey(selectedValue); // 直接传入最新选中值发请求 fetchItemsFilter(selectedValue); }; // 请求方法接收排序参数,默认兜底取当前状态值 const fetchItemsFilter = async (currentSortKey = sortByKey) => { try { const requestOptions = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ sort: [[currentSortKey, sortByOrder]], }), }; const res = await fetch(`${process.env.REACT_APP_BASE_URL}/api/ticket`, requestOptions); const jsonResponse = await res.json(); setIsLoaded(true); setTickets(jsonResponse); } catch (error) { setIsLoaded(true); setError(error); } };
这个方案的优势:
- 逻辑直观,不需要等组件重渲染,选中后立刻发请求,响应更快
- 不会出现useEffect监听导致的多余触发问题
方案2:useEffect监听状态触发请求(适合多入口修改状态的场景)
如果sortByKey会被下拉框之外的多个操作修改,且所有修改后都需要触发筛选,可以把请求逻辑放到useEffect中,监听状态变化自动执行:
const [sortByKey, setSortByKey] = useState(); // 下拉框回调只负责更新状态 const updateSortByKey = (e) => { setSortByKey(e.target.value); }; // 状态更新完成、组件重渲染后自动触发请求 useEffect(() => { // 跳过初始挂载时sortByKey为空的无效请求 if (!sortByKey) return; fetchItemsFilter(); }, [sortByKey]); const fetchItemsFilter = async () => { try { const requestOptions = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ // 此时闭包中的sortByKey已经是最新值 sort: [[sortByKey, sortByOrder]], }), }; const res = await fetch(`${process.env.REACT_APP_BASE_URL}/api/ticket`, requestOptions); const jsonResponse = await res.json(); setIsLoaded(true); setTickets(jsonResponse); } catch (error) { setIsLoaded(true); setError(error); } };
注意:useEffect的依赖数组必须包含所有内部用到的响应式变量,比如这里如果
sortByOrder也是状态值,需要一并加入依赖数组,否则同样会出现旧值问题。
原有代码问题修正
你原来的fetchItemsFilter存在两个容易出bug的写法:
- 混合使用
async/await和.then链式调用,外层await fetchItemsFilter()实际上不会等待请求完成 - 没有捕获fetch请求的网络错误,容易出现未捕获的 promise 异常
建议统一使用async/await加try/catch的写法处理异步请求,参考上面给出的修正后代码即可。
内容的提问来源于stack exchange,提问作者Dev. R
相关产品推荐
相关产品推荐

