React加载组件为什么在数据加载完成还是不消失?

南宫文君 阅读 35

我在用React写一个数据请求组件,加载动画在请求开始时显示了,但请求成功后却一直不消失,明明状态已经变成false了。这是怎么回事啊?

代码是这样写的,请求开始时我把isLoading设为true,成功后设为false。但实际运行时,加载图标一直卡着:


function ProductList() {
  const [products, setProducts] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    setIsLoading(true);
    fetch('/api/products')
      .then(res => res.json())
      .then(data => {
        setProducts(data);
        setIsLoading(false); // 这里确实执行了
      })
      .catch(err => {
        console.error(err);
        setIsLoading(false);
      });
  }, []);

  return (
    
{isLoading && } {/* 这个始终显示 */}
    {products.map(p => (
  • {p.name}
  • ))}
); }

我加了console.log确认过,请求成功时isLoading确实变成了false,但页面上的加载图标就是不消失,这是为什么?

我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
设计师宁馨
问题出在React的状态更新是异步的,你把setIsLoading(true)fetch写在一起,可能导致加载状态没及时刷新。改成这样:

useEffect(() => {
setIsLoading(true);

// 确保状态更新后再发起请求
Promise.resolve().then(() => {
fetch('/api/products')
.then(res => res.json())
.then(data => {
setProducts(data);
setIsLoading(false);
})
.catch(err => {
console.error(err);
setIsLoading(false);
});
});
}, []);


如果还不行,可能是其他地方影响了渲染,检查下父组件或样式。
点赞 6
2026-02-02 13:04
一世玉
一世玉 Lv1
问题出在你的代码逻辑上,虽然 isLoading 确实变成了 false,但由于 React 的状态更新是异步的,再加上你可能没注意到的一个细节:fetch 请求本身并不会自动终止组件的渲染流程。简单说,加载动画不消失的原因可能是状态更新和 DOM 更新不同步导致的。

这里有一个更好的写法,不仅可以解决你的问题,还能让代码更优雅:

首先,确保你的 useEffect 返回一个清理函数(cleanup function),这样如果组件卸载了,可以避免不必要的状态更新。

function ProductList() {
const [products, setProducts] = useState([]);
const [isLoading, setIsLoading] = useState(false);

useEffect(() => {
let isMounted = true; // 添加一个标识,确保组件挂载状态

setIsLoading(true);
fetch('/api/products')
.then(res => res.json())
.then(data => {
if (isMounted) { // 检查组件是否还挂载
setProducts(data);
setIsLoading(false);
}
})
.catch(err => {
if (isMounted) { // 同样检查一下
console.error(err);
setIsLoading(false);
}
});

return () => { // 清理函数
isMounted = false; // 卸载时设置为 false
};
}, []);

return (
<div>
{isLoading && <p>Loading...</p>} {/* 这个现在能正常消失了 */}

{!isLoading && products.length > 0 && (
<ul>
{products.map(p => (
<li key={p.id}>{p.name}</li>
))}
</ul>
)}

{!isLoading && products.length === 0 && (
<p>No products found.</p>
)}
</div>
);
}


改动点总结:
1. 加了一个 isMounted 标识,防止组件卸载后还更新状态。
2. 在 setIsLoading(false) 前加了 isMounted 检查,确保不会对已卸载的组件进行无意义的状态更新。
3. 调整了返回值部分的结构,避免潜在的渲染问题。

这个版本不仅解决了你的问题,还让你的代码更健壮、更清晰。React 里这种异步请求的场景其实挺常见的,记得养成好习惯,每次都要考虑组件的生命周期!
点赞 9
2026-01-30 12:07