React页面刷新因数据未加载崩溃,除&&运算符外有更佳方案吗?
解决React中API数据加载前的页面崩溃问题
在测试API调用的沙箱项目时,页面刷新会崩溃,原因是页面加载速度快于数据获取速度。用逻辑与(&&)运算符添加检查能修复问题,但还有几种更实用的替代方案:
崩溃的原始代码
import React, { useEffect, useState } from "react"; import { Heading } from "./components/Heading"; const URL = "https://api.sleeper.app/v1/league/867824542855376896"; function App() { const [data, setData] = useState(null); const getData = async () => { try { const res = await fetch(URL); const data = await res.json(); setData(data); } catch (err) { console.log(err); } }; useEffect(() => { getData(); }, []); console.log(data); return ( <> <Heading str="Hello world" /> <Heading str="Hello friend" /> <h1>{data.bracket_id}</h1> {data.roster_positions.map((pos, i) => { return <h1 key={i + 1}>{pos}</h1>; })} </> ); } export default App;
修复后的代码(使用&&)
import React, { useEffect, useState } from "react"; import { Heading } from "./components/Heading"; const URL = "https://api.sleeper.app/v1/league/867824542855376896"; function App() { const [data, setData] = useState(null); const getData = async () => { try { const res = await fetch(URL); const data = await res.json(); setData(data); } catch (err) { console.log(err); } }; useEffect(() => { getData(); }, []); console.log(data); return ( <> <Heading str="Hello world" /> <Heading str="Hello friend" /> <h1>{data && data.bracket_id}</h1> {data && data.roster_positions.map((pos, i) => { return <h1 key={i + 1}>{pos}</h1>; })} </> ); } export default App;
更优替代方案
1. 初始化状态为匹配数据结构的空值
将useState的初始值从null改为和API返回数据结构一致的空值,这样即使数据未加载完成,访问属性或调用map也不会报错:
// 初始值匹配API返回的结构 const [data, setData] = useState({ bracket_id: '', roster_positions: [] });
这种方法无需额外的条件判断,代码更简洁,适合数据结构固定的场景。
2. 使用可选链操作符(?.)替代逻辑与
ES2020引入的可选链操作符可以更简洁地处理空值判断,当左侧值为null或undefined时,会直接返回undefined,不会继续访问后续属性:
<h1>{data?.bracket_id}</h1> {data?.roster_positions?.map((pos, i) => { return <h1 key={i + 1}>{pos}</h1>; })}
相比&&,可选链在处理多层嵌套的属性时更清晰,避免了data && data.user && data.user.name这类冗长写法。
3. 添加加载状态,渲染加载提示
如果要提升用户体验,可以增加一个加载状态,在数据未就绪时显示加载提示,完全避免未定义数据的渲染:
import React, { useEffect, useState } from "react"; import { Heading } from "./components/Heading"; const URL = "https://api.sleeper.app/v1/league/867824542855376896"; function App() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const getData = async () => { try { const res = await fetch(URL); const data = await res.json(); setData(data); } catch (err) { console.log(err); } finally { setLoading(false); // 无论请求成功或失败,都结束加载状态 } }; useEffect(() => { getData(); }, []); // 加载中时显示提示 if (loading) { return <div>加载中...</div>; } return ( <> <Heading str="Hello world" /> <Heading str="Hello friend" /> <h1>{data.bracket_id}</h1> {data.roster_positions.map((pos, i) => { return <h1 key={i + 1}>{pos}</h1>; })} </> ); } export default App;
这种方式不仅解决了崩溃问题,还能让用户明确知道页面的加载状态,提升交互体验。
4. 使用错误边界捕获渲染异常
对于更复杂的应用,可以创建错误边界组件,用来捕获子组件渲染时的异常,并显示备用UI。错误边界是React提供的全局处理渲染错误的机制,适合需要统一处理异常场景的项目。
总结
你使用&&的做法是有效的,但上述方案各有优势:初始化匹配结构适合简单场景,可选链写法更简洁,加载状态提升用户体验,错误边界适合全局异常处理。可以根据项目的复杂度和需求选择合适的方案。
内容的提问来源于stack exchange,提问作者c0Ln
相关产品推荐
相关产品推荐

