如何在useEffect钩子完成数据请求后再渲染React组件
实现方案
首先要明确一个基础逻辑:useEffect 的执行时机是组件首次渲染挂载到DOM之后才触发,所以你没办法通过useEffect实现「组件渲染前就完成数据获取」的需求,我们分两种适用场景给出解决方案:
场景1:可接受先展示加载过渡态(官方推荐的常规实现)
这是绝大多数场景下的最优解,先渲染加载提示,等数据请求完成且写入状态后再渲染业务组件,修改后的代码如下:
import { useState, useEffect } from 'react' import axios from 'axios' import Home from './Home' export const App = () => { // 给状态添加初始值 const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) useEffect(() => { const fetchData = async () => { try { const res = await axios.get("/data") setData(res.data) } catch (err) { setError(err) console.error(err) } finally { setLoading(false) } } fetchData() }, []) // 加载中返回占位提示 if (loading) return <div>数据加载中...</div> // 报错返回错误提示 if (error) return <div>数据加载失败,请刷新重试</div> // 拿到数据后再渲染Home组件,可把data通过props传递给Home return ( <div> <Home data={data} /> </div> ) }
场景2:必须在组件渲染前拿到数据,无加载过渡
这种情况需要把数据请求逻辑提到组件渲染流程之外,有两种可落地的实现方式:
方式1:请求完成后再挂载根组件
把数据请求放在入口文件中,等接口返回数据后再初始化渲染React应用:
// 入口文件 main.jsx import axios from 'axios' import { createRoot } from 'react-dom/client' import App from './App' axios.get("/data").then(res => { const root = createRoot(document.getElementById('root')) // 把拿到的数据作为初始化props传入App root.render(<App initData={res.data} />) }).catch(err => console.error('数据加载失败', err)) // App组件直接使用props传入的初始数据 export const App = ({ initData }) => { const [data, setData] = useState(initData) return ( <div> <Home data={data} /> </div> ) }
方式2:使用Suspense(React 18+ 支持)
配合支持Suspense的请求库(如SWR、React Query),可以更优雅地实现预加载逻辑,由React统一处理加载状态:
import { Suspense, useState } from 'react' import useSWR from 'swr' import axios from 'axios' import Home from './Home' const fetcher = (url) => axios.get(url).then(res => res.data) const AppContent = () => { // 开启suspense模式后,会自动等待请求完成再渲染组件 const { data } = useSWR('/data', fetcher, { suspense: true }) const [data, setData] = useState(data) return <Home data={data} /> } export const App = () => { return ( <div> {/* fallback为加载阶段展示的内容,不需要可以留空 */} <Suspense fallback={<div></div>}> <AppContent /> </Suspense> </div> ) }
注意:完全取消加载态意味着用户打开页面到数据返回前会出现白屏,体验不如加载过渡方案,非特殊需求不建议使用。
内容的提问来源于stack exchange,提问作者user16131385
相关产品推荐
相关产品推荐

