You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React请求完成前展示加载状态内容?

React元素加载状态实现方案

嘿,这个需求我太熟了!在React里给<p>这类普通元素添加加载状态其实很简单,而且可以做得非常通用,不用每个元素都重复写逻辑。下面给你几种实用的方案,按需选择就行:

方案1:封装通用加载状态组件(最推荐,复用性拉满)

把加载逻辑、状态判断和UI封装成一个通用组件,不管是<p>还是其他元素都能直接套进去,后续改加载样式也只需要改这一个地方。

import { useState, useEffect } from 'react';

// 通用加载包装组件
function LoadingWrapper({ endpoint, renderContent }) {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setIsLoading(true);
        const response = await fetch(endpoint);
        if (!response.ok) throw new Error('请求失败,请稍后重试');
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setIsLoading(false);
      }
    };

    fetchData();
  }, [endpoint]);

  // 加载中状态:可以自定义成骨架屏、闪烁文字等
  if (isLoading) {
    return <p className="loading-skeleton">加载中...</p>;
  }

  // 错误状态
  if (error) {
    return <p className="error-text">出错了:{error}</p>;
  }

  // 渲染实际内容,把获取到的数据传进去
  return renderContent(data);
}

// 使用示例:给<p>套加载状态
function App() {
  return (
    <div className="app">
      <LoadingWrapper
        endpoint="/api/article-content"
        renderContent={(data) => (
          <p className="article-text">{data.content}</p>
        )}
      />
    </div>
  );
}

搭配一点CSS让加载状态更美观(比如骨架屏效果):

.loading-skeleton {
  background: linear-gradient(90deg, #f0f0f0 25%, #e5e5e5 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading-shimmer 1.5s infinite;
  color: transparent;
  border-radius: 4px;
}

@keyframes loading-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

.error-text {
  color: #dc2626;
}

方案2:组件内直接实现(适合简单场景)

如果只是单个元素需要加载状态,不想额外封装组件,直接在父组件里处理逻辑就行,快速又直接:

import { useState, useEffect } from 'react';

function ProfileBio() {
  const [bioText, setBioText] = useState('');
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    fetch('/api/user-bio')
      .then(res => res.json())
      .then(data => {
        setBioText(data.bio);
        setIsLoading(false);
      })
      .catch(() => {
        setBioText('加载失败,请刷新页面重试');
        setIsLoading(false);
      });
  }, []);

  return (
    <p className={isLoading ? 'loading-blink' : ''}>
      {isLoading ? '加载个人简介中...' : bioText}
    </p>
  );
}

对应的闪烁加载样式:

.loading-blink {
  color: #6b7280;
  animation: blink 1s infinite alternate;
}

@keyframes blink {
  from { opacity: 0.6; }
  to { opacity: 1; }
}

方案3:自定义Hook封装逻辑(逻辑与UI分离)

把数据获取、加载状态的逻辑抽成自定义Hook,组件只负责UI渲染,代码更干净,也方便复用逻辑:

import { useState, useEffect } from 'react';

// 自定义Hook:封装请求和加载状态
function useFetch(endpoint) {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setIsLoading(true);
        const res = await fetch(endpoint);
        if (!res.ok) throw new Error('请求异常');
        const result = await res.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setIsLoading(false);
      }
    };

    fetchData();
  }, [endpoint]);

  return { data, isLoading, error };
}

// 使用Hook的组件
function NewsDescription() {
  const { data, isLoading, error } = useFetch('/api/news-detail');

  if (isLoading) return <p className="loading-skeleton">加载新闻描述中...</p>;
  if (error) return <p>出错了:{error}</p>;
  return <p className="news-desc">{data?.description}</p>;
}

小Tips

  • 加载状态的UI可以根据设计需求调整:比如骨架屏、动画文字、占位符图标都可以,核心是让用户知道页面正在加载
  • 如果是多个元素需要加载状态,优先用方案1或3,避免重复代码
  • 可以给fetch添加超时处理,防止一直卡在加载状态

内容的提问来源于stack exchange,提问作者user7885981

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:49:37