使用Material UI Grid的React代码出现无限循环,如何规避重渲染问题?
问题原因
你触发无限循环的核心原因是在组件渲染的过程中直接调用状态更新方法(setFirstTime、setCurrentGroup、setPrintCurrentGroup):
- React 组件在调用
setXXX更新状态后会触发重渲染,重渲染时会重新执行videos.map逻辑,再次调用getVideoCard getVideoCard里又会再次更新状态,如此反复就形成了无限循环
解决方案
你的需求是按视频分类分组展示、每个分类只展示一次分类标题,完全不需要通过组件状态来记录当前分组,直接预处理videos数据按分类分组即可,逻辑更简洁也不会触发重渲染问题。
修改后的完整组件代码如下:
import React, { useEffect, useMemo } from 'react'; import VideoCardComponent from './VideoCard'; import Grid from '@mui/material/Grid'; import { connect } from 'react-redux'; import { getVideos } from '../redux/actions/videosActions&Consts'; import { Typography } from '@mui/material'; const Content = ({ getVideos, videos, loaded }) => { // 补充useEffect的依赖,符合Hook规则,loaded变化时可自动重新触发请求 useEffect(() => { if (!loaded) { getVideos(); } }, [loaded, getVideos]); // 预处理:将视频按分类分组,用useMemo缓存,仅当videos变化时重新计算 const groupedVideos = useMemo(() => { const groups = {}; videos.forEach(video => { const category = video.category_name; if (!groups[category]) groups[category] = []; groups[category].push(video); }); // 转成[分类名, 分类下视频数组]的格式方便遍历,保留原数组中分类首次出现的顺序 return Object.entries(groups); }, [videos]); return ( <Grid container spacing={1}> {groupedVideos.map(([categoryName, videoList]) => ( <React.Fragment key={categoryName}> {/* 分类标题独占一行 */} <Grid item xs={12}> <Typography variant="h4">{categoryName}</Typography> </Grid> {/* 渲染当前分类下的所有视频卡片 */} {videoList.map(videoObj => ( <Grid item xs={4} key={videoObj.id}> <VideoCardComponent {...videoObj} /> </Grid> ))} </React.Fragment> ))} </Grid> ); }; function mapStateToProps(state) { return { videos: state.videosReducer.videos, loaded: state.videosReducer.loaded }; } function mapDispatchToProps(dispatch) { return { getVideos: () => dispatch(getVideos()) }; } export default connect(mapStateToProps, mapDispatchToProps)(Content);
额外优化建议
所有循环渲染的列表项请添加唯一的key属性,优先用业务唯一ID(比如视频ID),不要用数组索引,避免出现渲染异常。
内容的提问来源于stack exchange,提问作者Rafael
相关产品推荐
相关产品推荐

