为什么React Hooks组件中fetch请求到的数据没有正常显示?
问题原因
setOfferings是React提供的异步更新方法,调用后不会立刻修改当前作用域下的offerings变量,而是会把更新任务推入队列,等当前渲染周期结束后才会触发重渲染更新变量值,所以你在setOfferings后立刻打印拿到的永远是当前渲染周期的旧值(也就是初始的空数组)。- 直接给
useEffect传入async函数是错误写法:useEffect期望返回值是可选的清理函数,而async函数默认返回Promise,会导致清理逻辑失效,甚至引发内存泄漏。
解决方法
1. 新增加载状态控制渲染逻辑
新增isLoading状态标记数据加载进度,加载完成前显示占位内容,加载完成后再渲染业务组件,避免提前展示无数据的提示。
2. 修正异步逻辑写法
把异步逻辑封装在useEffect内部的自执行函数中,避免直接给useEffect传async函数,同时添加请求错误捕获逻辑避免页面崩溃。
3. 调整状态打印逻辑
如果需要查看更新后的offerings值,可以单独用useEffect监听offerings变化后再打印,或者直接打印接口返回的原始数据。
修正后参考代码
import { useState, useEffect, useDispatch, useSelector } from 'react'; // 其他导入省略 const HomeNew = () => { const [offerings, setOfferings] = useState([]); // 新增加载状态 const [isLoading, setIsLoading] = useState(true); // 可选:新增错误状态 const [loadError, setLoadError] = useState(null); const loadData = async () => { try { setIsLoading(true); setLoadError(null); const res = await fetch(`http://52.207.83.69${CRUD_OFFERING}`); if (!res.ok) throw new Error('请求失败'); const result = await res.json(); setOfferings(result); // 要查看接口返回的数据直接打印result即可 console.log(result, '接口返回的offerings数据'); } catch (err) { setLoadError(err.message); console.error('加载数据失败:', err); } finally { setIsLoading(false); } }; useEffect(() => { navbarToggle(); // 在内部调用异步函数,不要给useEffect直接传async (async () => { await loadData(); })(); }, []); // 监听offerings变化,打印更新后的值 useEffect(() => { console.log(offerings, '更新后的offerings'); }, [offerings]); const dispatch = useDispatch(); const modalState = useSelector((state) => state.modal); const modalToggle = () => { dispatch({ type: MODAL_TOGGLE, payload: !modalState.show, }); ga.event("navbar_requestdemo_clicked"); }; const navbarOpenState = useSelector((state) => state.navbar); const navbarToggle = () => { if (!navbarOpenState.open) return; dispatch({ type: NAVBAR_OPEN, payload: false, }); }; // 加载中状态展示 if (isLoading) { return <div className="text-center py-5">数据加载中...</div>; } // 加载失败状态展示 if (loadError) { return <div className="text-center py-5 text-danger">加载失败:{loadError}</div>; } return ( <div className="d-flex justify-content-center align-items-center bg-color-white fc-px-15" onClick={navbarToggle} > <div className={homeStyles["padded-body"] + " col-11 p-0"}> <div className=" position-relative bg-color-white"> <div className={homeStyles["img-holder"]}></div> <div className="col-12 column position-absolute top-0 d-flex justify-content-center"> <div className="col-lg-6 col-12 fc-mt-2"> <SearchBar /> </div> </div> <div className="position-absolute top-50 translateY-middle"> <div className="position-relative"> <h1 className={`${homeStyles["hero-text"]} font-weight-bolder`}> Building <br /> Meaningful <br /> Engagement </h1> <button className="btn btn-primary-round mt-3 px-3 py-2" onClick={() => { modalToggle(); }} > Request access </button> </div> </div> </div> <div id={homeStyles["discover-section"]} className="d-flex justify-content-center align-items-center" > <div className="col-12 column"> <h4 className="font-weight-bold">Discover</h4> <div id={homeStyles["offer-section"]} className="row justify-content-center align-items-center" > {!offerings?.length && <h4 className="text-center">There are no active offerings.</h4> } </div> <OfferingCarousal offeringsList={offerings} name={"Offerings"} /> <div id={homeStyles["consultancy-section"]} className=""> <div className="row"> <div className="d-flex justify-content-center align-items-center col-lg-6 col-12 px-0 mt-3 mb-4" id={homeStyles["consultancy-div"]} > <div className="col-12 column p-5"> <h1 className="font-weight-bold">Add your consultancy</h1> <h5 className="mt-4"> Reach more people and organizations </h5> <Link href="/consultancies"> <button className="btn btn-primary-round mt-4"> Learn more </button> </Link> </div> </div> <div className="col-lg-6 col-12 px-0"> <img src="/images/Rachael_glasses_home_page.jpg" id={homeStyles["consultant-img"]} className="mt-3" alt="咨询顾问" /> </div> </div> </div> </div> </div> </div> </div> ); }; export default HomeNew;
内容的提问来源于stack exchange,提问作者Billy Keef
相关产品推荐
相关产品推荐

