如何在获取服务器数据后渲染React组件?问题排查
解决方案
你的问题核心是异步获取用户数据时,组件已完成初始渲染,导致Home组件一开始拿不到有效数据。可以通过添加加载状态解决,同时React本身会在状态更新时自动触发重渲染,确保数据就绪后组件能同步更新内容。
步骤1:在Layout中添加加载状态
修改Layout.js,增加加载状态标记,在数据获取完成前显示加载提示,避免渲染未填充的内容:
import React, { useEffect, useState } from 'react'; import { Outlet } from "react-router-dom"; import Navbar from './Navbar'; function Layout() { const [currentUser, setCurrentUser] = useState({ name: "", email: "", signedIn: false, admin: false }); // 新增加载状态,初始为true const [isLoading, setIsLoading] = useState(true); const getCurrentUser = async () => { try { const res = await fetch('/userinfo', { method: "GET", headers: { Accept: "application/json", "Content-Type": "application/json" }, credentials: "include" }); const data = await res.json() if (res.status !== 200 || !data) { const error = new Error(res.error); throw error; } else { const { name, email, admin } = data.userInfo; setCurrentUser({name, email, admin, signedIn: true}); } } catch (err) { console.log(err.message); // 请求失败时保持默认用户状态,可根据需求调整 } finally { // 无论请求成功或失败,都结束加载状态 setIsLoading(false); } }; useEffect(() => { getCurrentUser(); }, []); const setUserInfo = (data) => { setCurrentUser(data); }; // 加载中时显示加载提示 if (isLoading) { return <div className="flex justify-center items-center h-screen">加载中...</div>; } return ( <div> <Navbar signedInfo={currentUser} setSignedInfo={setUserInfo} /> <div> <Outlet context={[currentUser, setUserInfo]} /> </div> </div> ); } export default Layout;
步骤2:优化Home组件的初始渲染(可选)
如果不想完全隐藏内容,也可以在Home组件中判断用户登录状态,避免显示空的用户名:
import React from 'react' import { useNavigate, useOutletContext } from 'react-router-dom' function Home() { const navigate = useNavigate(); const [currentUser] = useOutletContext(); const redirectTo = () => { if(currentUser.signedIn) { navigate('/labs'); } else { navigate('/signin') } } return ( <div className='flex flex-col items-center space-y-10 animate-fadeIn'> <h1 className="text-3xl pt-32 text-center font-semibold font-sans md:text-4xl lg:text-5xl"> Welcome {/* 仅在用户登录时显示用户名 */} <span className='text-blue-500'>{currentUser.signedIn ? ` ${currentUser.name}` : ''}</span> <br /> To Control System Engineering Labs </h1> <p className='text-center mx-5 md:max-w-3xl'>Control systems are everywhere, from the tiniest dial functioning inside your watch to the gigantic satellite revolving around the planet. They constantly synchronise the behaviour of devices in a recurrent and predicted way.</p> <button onClick={redirectTo} className="inline-block px-4 py-2 text-white bg-blue-600 rounded-md shadow hover:bg-blue-700 focus:bg-blue-700 focus-outline:none active:bg-blue-800 transition duration-150 ease-in-out">Get Started</button> </div> ) } export default Home
原理说明
- 当
getCurrentUser异步请求完成后,setCurrentUser会更新Layout的状态,触发Layout重渲染,此时Outlet的context同步更新,Home组件通过useOutletContext获取到最新用户数据,自动触发重渲染。 - 加载状态的作用是在数据未就绪时,避免渲染不完整内容,提升用户体验。
内容的提问来源于stack exchange,提问作者UHpi
相关产品推荐
相关产品推荐

