React嵌套函数中第二个函数无法获取useState更新ID的问题
问题原因
你的代码存在两个核心逻辑错误,导致id无法正常被第二个请求读取:
fetch是异步非阻塞方法,你发起第一个接口请求后,不会等接口返回、setId执行完成,就会立刻同步执行getCMSPage,此时读取到的id永远是初始值。- React的
useState更新是异步的,状态更新后需要等组件下一次重渲染,才能在新的作用域中拿到最新值。你在同一次函数执行的闭包里,永远拿不到setId更新后的id值。 - 额外细节问题:你声明id状态的初始值是带空格的字符串
' ',并非你描述的空字符串'',该问题不影响核心报错。
连续两次保存文件时功能正常,是热更新带来的偶发现象:第一次保存触发的请求已经把id写入状态,第二次保存触发热重载时,组件重新执行会读取到上一次缓存的id值,和代码逻辑正确性无关。
修复方案
根据你的业务场景二选一即可:
方案1:链式调用(无多余状态,性能最优)
如果id不需要在组件其他位置复用,完全没必要把id存入state,拿到第一个接口的返回值后直接发起第二个请求即可,减少一次无意义的组件重渲染:
const [loading, setLoading] = useState(true); const [data, setData] = useState([]); const fetchCMSContent = () => { const baseConfig = { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'sw-access-key': `${API_KEY}`, }, }; fetch(`${URL}/store-api/category`, baseConfig) .then(res => res.json()) .then(categoryRes => { const cmsId = categoryRes.elements[0].cmsPageId; return fetch(`${URL}/store-api/cms/${cmsId}`, baseConfig); }) .then(res => res.json()) .then(cmsRes => { setData(cmsRes.sections); setLoading(false); }) .catch(err => console.error('请求异常:', err)); }; useEffect(() => { fetchCMSContent(); }, []);
方案2:监听id变化触发请求(适合id需要跨逻辑复用的场景)
如果id需要在组件其他逻辑中使用,必须存入state,就拆分请求逻辑,用useEffect监听id的变化,等id更新为有效值后再发起第二个请求:
const [loading, setLoading] = useState(true); const [data, setData] = useState([]); const [id, setId] = useState(''); // 修正初始值为真正的空字符串 // 第一个effect仅负责获取id useEffect(() => { const requestConfig = { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'sw-access-key': `${API_KEY}`, }, }; fetch(`${URL}/store-api/category`, requestConfig) .then(res => res.json()) .then(res => setId(res.elements[0].cmsPageId)) .catch(err => console.error('分类接口请求失败:' + err)); }, []); // 监听id变化,id存在时才发起cms页面请求 useEffect(() => { if (!id) return; const requestConfig = { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'sw-access-key': `${API_KEY}`, }, }; fetch(`${URL}/store-api/cms/${id}`, requestConfig) .then(res => res.json()) .then(cmsRes => { setData(cmsRes.sections); setLoading(false); }) .catch(err => console.error('CMS接口请求失败:' + err)); }, [id]);
内容的提问来源于stack exchange,提问作者user18628737
相关产品推荐
相关产品推荐

