如何解决React Accordion点击时子组件重复渲染导致的卡顿问题
解决方案
核心问题原因
你已经给子组件加了React.memo但还是触发重渲染,本质是React.memo默认做浅比较,你传给子组件的引用类型prop在父组件每次重渲染时都生成了新的引用,导致浅比较判定props变化,触发子组件重渲染,具体包括:
- 父组件传给子组件的
classes是父组件调用样式钩子生成的对象,父组件每次因Accordion状态变化重渲染时,都会生成新的classes引用 - 子组件内部的
useMemo没有实际优化效果,仅透传了data参数 - 所有Accordion的子组件默认全量渲染,无论是否展开,每次点击都会触发所有子组件的重渲染校验
可落地优化步骤
1. 调整子组件React.memo比较逻辑
删除子组件内无效的Memodata定义,给React.memo增加自定义比较函数,仅在业务相关的data、title变化时才触发重渲染,忽略其他无关prop的引用变化:
// 子组件删除以下无效代码 // const Memodata = React.useMemo(() => { // return data // },[data]); // 导出改为自定义比较逻辑 export default React.memo(childComponent, (prevProps, nextProps) => { // 仅data和title变化时才重渲染子组件 return prevProps.data === nextProps.data && prevProps.title === nextProps.title })
如果样式不需要动态变更,更推荐将子组件的样式定义移到子组件内部,无需从父组件传classes,从根源消除这个可变引用prop。
2. 父组件固定引用类型prop的引用
如果必须从父组件传classes、cells这类引用类型参数,在父组件内用useMemo包裹保证引用不变:
// 父组件内固定配置类数组/对象的引用 const chargesCells = useMemo(() => [/* 你的配置项 */], []) const signatoriesCells = useMemo(() => [/* 你的配置项 */], []) const memoClasses = useMemo(() => classes, [])
传参时使用固定引用的变量即可。
3. 按需渲染Accordion内容(收益最高的优化)
仅在当前Accordion处于展开状态时,才渲染内部的子组件,未展开的Accordion不会加载子组件,从根源避免不必要的重渲染:
<AccordionDetails> {expanded === i && ( <Grid item xs={12}> {/* 原有的三个子组件代码 */} <DetailsCards companyName="Name" row={row} mainDetailData={corporateCells} show={show} setShow={setShow} /> <DownloadsChargesCard data={MemoUserHistorySummary?.charges} title={"Charges Registered"} cells={chargesCells} classes={memoClasses} /> <DownloadDiractorCard data={MemoUserHistorySummary?.directors_history} title={"Directors List"} cells={signatoriesCells} classes={memoClasses} /> </Grid> )} </AccordionDetails>
4. 列表渲染优化
- 给子组件内
map渲染的列表项增加唯一key属性,不要使用数组index作为key,优先使用行数据的唯一ID如CHARGE_ID - 将空数据判断逻辑移到
map外部,避免每次循环重复判断,同时修复空数据时重复渲染无数据提示的问题
内容的提问来源于stack exchange,提问作者user12302978
相关产品推荐
相关产品推荐

