React设置状态变量无效果:useEffect内更新savedIds后值始终为空
问题原因
- React 状态更新为异步批量执行逻辑,调用
setSavedItems(json)后,当前作用域内的savedItems还是本次渲染初始的空数组,不会立刻变为接口返回的新值,后续执行savedItems.map时遍历的是空数组,因此savedIds会被设置为空。 - 你的
useEffect依赖数组为空,但内部用到了props.token,如果后续token发生变化,该副作用不会重新执行,存在潜在逻辑问题。
修复方案
可根据实际场景选择以下任意一种修复方式:
方案1:直接用接口返回值生成ids数组
不需要等待savedItems状态更新,拿到接口返回数据后直接生成ids数组同时更新两个状态即可:
.then((json) => { if (isMounted) { setSavedItems(json) // 直接用接口返回的json生成ids,额外加Number转换匹配你要的数字格式 const idsArray = json.map((item) => Number(item.site_id)) setSavedIds(idsArray) } })
方案2:拆分副作用,监听savedItems变化自动更新ids
如果你需要savedItems每次变化都自动同步更新savedIds,可以拆分出单独的副作用逻辑:
// 原useEffect仅负责请求数据更新savedItems,补充props.token到依赖数组 useEffect(() => { let isMounted = true; if (props.token) { fetch(url, { method: 'GET', credentials: 'include', headers: { 'Content-Type': 'application/json', 'Authorization': 'Token ' + props.token, } }) .then((response) => response.json()) .then((json) => { if (isMounted) setSavedItems(json) }) .catch((error) => console.error(error)) .finally(() => isMounted = false); } }, [props.token]); // 新增useEffect监听savedItems变化,自动生成savedIds useEffect(() => { const idsArray = savedItems.map((item) => Number(item.site_id)) setSavedIds(idsArray) }, [savedItems])
优化建议
如果savedIds完全是派生自savedItems的状态,你甚至可以不用单独将其存为state,每次渲染时直接计算即可,避免多余的状态同步问题:
const [savedItems, setSavedItems] = useState([]); // 直接计算派生值,savedItems变化时会自动更新 const savedIds = savedItems.map(item => Number(item.site_id))
内容的提问来源于stack exchange,提问作者Damian
相关产品推荐
相关产品推荐

