如何优化useEffect含两个await、表格渲染慢的React应用性能?
优化方案
1. 修复useEffect无限执行问题
当前你写的useEffect没有传入依赖数组,会在组件每次渲染后重复执行接口请求逻辑,导致反复拉取数据、重复渲染,是性能卡顿的核心原因之一。
修改为仅在组件挂载时执行一次,给useEffect添加空依赖数组:
// App.jsx 中修改useEffect useEffect(() => { const getDataFromApi = async () => { // 原有逻辑不变 }; getDataFromApi(); }, []); // 加空依赖数组,仅挂载执行一次
2. 改为并行请求接口
当前两个fetch是串行执行,必须等第一个国家列表接口返回后才会发起第二个全局统计接口请求,双倍拉长了接口耗时。两个接口无依赖关系,可以用Promise.all并行发起请求,降低总等待时间:
const getDataFromApi = async () => { // 并行发起两个请求,不用等第一个返回再发第二个 const [responseForCountriesData, responseForCategories] = await Promise.all([ fetch("https://disease.sh/v3/covid-19/countries"), fetch("https://disease.sh/v3/covid-19/all") ]); // 后续解析逻辑不变 const dataForCountriesData = await responseForCountriesData.json(); const dataForCategories = await responseForCategories.json(); // ... 原有赋值逻辑 };
3. 表格添加虚拟滚动
当前表格一次性渲染所有国家的行数据,数据量较大时首次渲染压力高。你可以用虚拟滚动方案仅渲染可视区域内的行,不需要全量渲染DOM,大幅降低表格渲染压力:
你可以使用react-window实现,修改CasesTable.jsx代码示例:
import React from "react"; import { Table } from "react-bootstrap"; import { FixedSizeList as List } from "react-window"; const CasesTable = ({ data }) => { // 渲染单行的方法 const renderRow = ({ index, style }) => { const elem = data[index]; return ( <tr style={style} onClick={() => { navigator.clipboard.writeText(`国家/地区: ${elem.country} 确诊数: ${elem.cases} `); alert("国家和确诊数已复制到剪贴板"); }} key={elem.country} > <td>{elem.country}</td> <td>{elem.cases}</td> </tr> ); }; return ( <> <p style={{ color: "red" }}>点击行即可复制对应信息 😉</p> <div className="table_div" style={{ height: "80vh", overflow: "scroll" }}> <Table striped bordered variant="dark" className="table" > <thead> <tr> <th>国家/地区</th> <th>确诊病例数</th> </tr> </thead> <tbody> <List height={window.innerHeight * 0.8} // 对应容器高度80vh itemCount={data.length} itemSize={35} // 每行高度,可自行调整 width="100%" > {renderRow} </List> </tbody> </Table> </div> </> ); }; export default CasesTable;
4. 批量更新state减少重渲染
当前你在接口返回后连续调用6次setState,每次setState都会触发组件重渲染,你可以把多个状态合并为一个state对象,一次性更新,减少重渲染次数:
// App.jsx 中合并状态 const [stats, setStats] = useState({ confirmed: { addedTxt: 1111, presentTxt: 1111 }, active: { addedTxt: 1111, presentTxt: 1111 }, recovered: { addedTxt: 1111, presentTxt: 1111 }, deceased: { addedTxt: 1111, presentTxt: 1111 }, countryTableData: [] }); // 接口返回后一次性更新 setStats({ confirmed: { addedTxt: dataForCategories.todayCases, presentTxt: dataForCategories.deaths }, active: { addedTxt: `-`, presentTxt: dataForCategories.active }, recovered: { addedTxt: dataForCategories.todayRecovered, presentTxt: dataForCategories.recovered }, deceased: { addedTxt: dataForCategories.todayDeaths, presentTxt: dataForCategories.deaths }, countryTableData: sortedData });
5. 新增数据缓存策略
可以把接口返回的结果存在localStorage中,设置1-2小时的缓存有效期,用户下次刷新页面时优先读取本地缓存,不用重新发起请求,直接渲染数据,大幅提升二次访问速度。
内容的提问来源于stack exchange,提问作者Aviral
相关产品推荐
相关产品推荐

