React中大数据集变量赋值避免重置的最优方案咨询
最优赋值方案
针对大型数据集的场景,推荐以下几种方案,既避免useState带来的不必要重渲染,又解决普通变量随组件重渲染被重置的问题:
1. 使用useRef存储大型数据
useRef的.current属性不会随组件重渲染被重置,适合存储不需要触发全局UI更新的大型数据集(Recharts图表会自动监听传入的data变化,只要数据更新后组件能获取到最新值即可)。
修改你的代码示例:
export default function Page(){ // ... 保留原有状态定义 const pieChartDataRef = React.useRef<any[]>([]); const barChartDataRef = React.useRef<any[]>([]); const treeMapDataRef = React.useRef<any[]>([]); useEffect(() => { switch (selectedOrganisation) { case ALUAN_COCONUTS: // 对应企业的数据处理逻辑 break; case BLANEY_FARM: // 对应企业的数据处理逻辑 break; case MOORLANDS_LAMB: pieChartDataRef.current = getSpeciesClassesSummaryWithinDateRange(MoorlandsPieChartData, sliderDates[0], sliderDates[1],reportFilters.class_name); barChartDataRef.current = getSpeciesClassesWithinDateRange(MoorlandsPieChartData, sliderDates[0], sliderDates[1],reportFilters.class_name); treeMapDataRef.current = getTreeMapDataFromFeatureCollection(MoorlandsSpeciesData as FeatureCollection,sliderDates[0], sliderDates[1], reportFilters.class_name); break; default: pieChartDataRef.current = []; barChartDataRef.current = []; treeMapDataRef.current = []; } },[selectedOrganisation, sliderDates, reportFilters.class_name]); // 渲染图表时直接使用ref.current return ( // ... 保留原有结构 <Treemap data={treeMapDataRef.current} // ... 其他属性不变 > { treeMapDataRef.current.map((entry, index) => ( <Cell key={`cell-${index}`} fill={CHART_FILL_COLOURS.find(color => color.dataKey == entry.name)?.fill} /> ))} <Tooltip /> </Treemap> // ... ) }
2. 使用useMemo缓存计算结果
如果数据需要根据状态动态计算且计算开销较大,useMemo可以缓存计算结果,只有当依赖项变化时才重新计算,同时返回的值可直接用于渲染,避免不必要的重复计算。
示例:
export default function Page(){ // ... 保留原有状态定义 const chartData = React.useMemo(() => { let pieData: any[] = []; let barData: any[] = []; let treeMapData: any[] = []; switch (selectedOrganisation) { case ALUAN_COCONUTS: // 对应企业的数据处理逻辑 break; case BLANEY_FARM: // 对应企业的数据处理逻辑 break; case MOORLANDS_LAMB: pieData = getSpeciesClassesSummaryWithinDateRange(MoorlandsPieChartData, sliderDates[0], sliderDates[1],reportFilters.class_name); barData = getSpeciesClassesWithinDateRange(MoorlandsPieChartData, sliderDates[0], sliderDates[1],reportFilters.class_name); treeMapData = getTreeMapDataFromFeatureCollection(MoorlandsSpeciesData as FeatureCollection,sliderDates[0], sliderDates[1], reportFilters.class_name); break; default: // 默认空数据 } return { pieData, barData, treeMapData }; }, [selectedOrganisation, sliderDates, reportFilters.class_name]); // 渲染时使用chartData中的对应数据 return ( // ... 保留原有结构 <Treemap data={chartData.treeMapData} // ... 其他属性不变 > { chartData.treeMapData.map((entry, index) => ( <Cell key={`cell-${index}`} fill={CHART_FILL_COLOURS.find(color => color.dataKey == entry.name)?.fill} /> ))} <Tooltip /> </Treemap> // ... ) }
3. 拆分图表子组件
将每个图表封装成独立子组件,把依赖项(selectedOrganisation、sliderDates等)作为props传入,子组件内部处理数据计算。这样父组件重渲染时,只有当子组件的props变化时才会重新计算数据,减少不必要的计算开销,同时提升代码可维护性。
示例子组件:
interface TreeMapChartProps { selectedOrg: string; sliderDates: number[]; reportFilters: any; } const TreeMapChart = ({ selectedOrg, sliderDates, reportFilters }: TreeMapChartProps) => { const treeMapData = React.useMemo(() => { if (selectedOrg === MOORLANDS_LAMB) { return getTreeMapDataFromFeatureCollection(MoorlandsSpeciesData as FeatureCollection,sliderDates[0], sliderDates[1], reportFilters.class_name); } // 其他企业的处理逻辑 return []; }, [selectedOrg, sliderDates, reportFilters.class_name]); return ( <div className="treemap-chart-wrapper"> <Treemap width={500} height={250} data={treeMapData} isAnimationActive={false} nameKey="name" dataKey="size" type="nest" nestIndexContent={item => { return <div>{`${item.name || 'root'}`}</div>; }} > { treeMapData.map((entry, index) => ( <Cell key={`cell-${index}`} fill={CHART_FILL_COLOURS.find(color => color.dataKey == entry.name)?.fill} /> ))} <Tooltip /> </Treemap> <p>Relative composition of species by type</p> </div> ); }; // 父组件中使用 export default function Page(){ // ... 保留原有状态定义 return ( // ... 保留原有结构 <Grid item xs={6} md={6}> <TreeMapChart selectedOrg={selectedOrganisation} sliderDates={sliderDates} reportFilters={reportFilters} /> </Grid> // ... ) }
方案选择建议
- 如果数据仅用于图表展示、不需要触发全局UI重渲染,优先选
useRef; - 如果数据需要根据状态动态计算且要缓存结果,选
useMemo; - 如果图表数量多、逻辑复杂,拆分组件更利于维护和性能优化。
内容的提问来源于stack exchange,提问作者MillturnK
相关产品推荐
相关产品推荐

