React/Next.js组件提前加载数据问题:如何等待getArticles()后渲染UI?
在React/Next.js中等待数据加载完成后渲染UI的解决方案
一、通用React场景:利用状态管理的加载状态
既然使用了useDispatch,说明项目大概率基于Redux(或类似状态管理库)。核心思路是给blog状态新增加载状态(loading)和错误状态(error),通过追踪这些状态控制UI渲染逻辑:
1. 完善Action逻辑,添加加载状态标记
在获取文章的Action中,分三个阶段更新状态:请求发起时标记加载中,请求成功后更新数据并结束加载,请求失败时记录错误并结束加载:
// actions/blogActions.js export const getArticles = () => async (dispatch) => { // 标记加载开始 dispatch({ type: 'GET_ARTICLES_LOADING' }); try { const res = await fetch('/api/articles'); const articles = await res.json(); // 请求成功,更新文章数据 dispatch({ type: 'GET_ARTICLES_SUCCESS', payload: articles }); } catch (err) { // 请求失败,记录错误信息 dispatch({ type: 'GET_ARTICLES_FAILURE', payload: err.message }); } };
2. 更新Reducer维护状态
在Reducer中处理上述Action,维护loading、articles、error三个核心状态:
// reducers/blogReducer.js const initialState = { articles: [], loading: false, error: null }; export default function blogReducer(state = initialState, action) { switch (action.type) { case 'GET_ARTICLES_LOADING': return { ...state, loading: true, error: null }; case 'GET_ARTICLES_SUCCESS': return { ...state, loading: false, articles: action.payload }; case 'GET_ARTICLES_FAILURE': return { ...state, loading: false, error: action.payload }; default: return state; } }
3. 组件中根据状态渲染UI
在组件中读取loading、articles、error状态,分别渲染加载提示、文章列表、错误信息:
import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { getArticles } from '../actions/blogActions'; function Blog() { const dispatch = useDispatch(); const { articles, loading, error } = useSelector(state => state.blog); useEffect(() => { dispatch(getArticles()); }, [dispatch]); // 加载中时显示加载提示 if (loading) { return <div>加载中...</div>; } // 加载失败时显示错误信息 if (error) { return <div>加载失败:{error}</div>; } // 数据就绪后渲染文章列表 return ( <div> {articles.map((item) => ( <div key={item.id}>{item.name}</div> ))} </div> ); } export default Blog;
二、Next.js专属方案:预渲染数据获取
Next.js提供三种预渲染数据获取方式,能在组件渲染前就拿到数据,彻底避免客户端useEffect带来的延迟:
1. 静态生成(SSG)- getStaticProps
适合数据不频繁更新的场景,构建时一次性获取数据生成静态页面,性能最优:
// pages/blog.js // 该函数在构建时执行(服务器端) export async function getStaticProps() { const res = await fetch('https://你的API地址/articles'); const articles = await res.json(); return { props: { articles }, // 将数据作为props传递给组件 revalidate: 60, // 可选:每隔60秒重新生成页面(增量静态再生) }; } // 组件直接接收预获取的articles function Blog({ articles }) { return ( <div> {articles.map((item) => ( <div key={item.id}>{item.name}</div> ))} </div> ); } export default Blog;
2. 服务端渲染(SSR)- getServerSideProps
适合数据需要实时更新的场景,每次用户请求时在服务器端获取最新数据:
// pages/blog.js // 该函数在每次用户请求时执行(服务器端) export async function getServerSideProps() { const res = await fetch('https://你的API地址/articles'); const articles = await res.json(); return { props: { articles }, }; } function Blog({ articles }) { return ( <div> {articles.map((item) => ( <div key={item.id}>{item.name}</div> ))} </div> ); } export default Blog;
3. 客户端兜底:可选链避免报错
如果必须在客户端获取数据,除了加载状态,还可以用可选链操作符?.避免blog.articles为undefined时的报错,但这仅为兜底方案,仍建议配合加载状态使用:
{blog.articles?.map((item) => ( <div key={item.id}>{item.name}</div> ))}
内容的提问来源于stack exchange,提问作者kittu
相关产品推荐
相关产品推荐

