React - 错误:重新渲染太多。 React 限制渲染次数以防止无限循环

时间:2021-04-05 17:51:12

标签: javascript reactjs

一直卡在这个错误上:Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. 经过调试,我想我找到了最后一个罪魁祸首。它与接下来的组件有关。但是我不知道为什么它们会导致渲染问题。

export default function GetUserBuckets()
{
    const ListLoading = LoadingComponent(UserBuckets);
    const [appState, setAppState] = useState({
        loading: true,
        posts: null,
    });


    useEffect(() => {
        if (!appState.loading) return;
    
        axiosInstance.get('all/buckets/').then((res) => {
            const allBuckets = res.data;
            setAppState({ loading: false, buckets: allBuckets });
        });
    }, []);

    
    return (
            <ListLoading isLoading={appState.loading} buckets={appState.buckets} />

    );
};

这是孩子: 这是一个加载组件,基本上显示一个加载指示器,当加载完成时,它会显示原始的Component

export function LoadingComponent(Component) {
    return function LoadingComponent({ isLoading, ...props }) {
        if (!isLoading) return <Component {...props} />;
        return (
        <Container  style={{justifyContent:"center",display:"flex", padding:"5rem"}} className="loadingCircle">
            <CircularProgress />
        </Container>
        );
    };
}
export default LoadingComponent;

这是它加载的组件。我很确定错误就在这里的某个地方。但是我找不到它?

const UserBuckets = (props) => {
    const { buckets } = props;
    console.log(buckets[0].id)
    const [openDeletePopUp, setOpenDeletePopUp] = useState(false);
    const [bucketName, setBucketName] = useState('');
    const [openEditPopUp, setOpenEditPopUp] = useState(false);
    const [bucketId, setBucketId] = useState(null)
    const randomStocks = Math.floor(Math.random() * buckets.stock_count);

    const [anchorEl, setAnchorEl] = React.useState(null);

    const [currentIndex, setCurrentIndex] = useState(0);

    const theme = useTheme()

    const classes = useStyles();

    const handleClick = (index) => (event) => {
        setAnchorEl(event.currentTarget);
        setCurrentIndex(index);
      };
  
    const handleClickDeleteOpen = (bucket, id) => {
        setOpenDeletePopUp(true);
        setBucketName(bucket)
        setBucketId(id)
    };
    
    const handleClickEditOpen = () => {
        setOpenEditPopUp(true);
      };
      
  
      const handleClose = () => {
        setAnchorEl(null);
      };
    
      const handleDeleteClose = () => {
        setOpenDeletePopUp(false);
      };

    console.log(buckets && buckets)

    if (!buckets || buckets.length === 0) return <p>Can not find any buckets, make one below!</p>;
    return (
        <React.Fragment>
            <Container style={{width:"90%"}} maxWidth="md" component="main">
                <Grid container spacing={5} alignItems="stretch">
                    {buckets.map((bucket, index) =>
                    {
                    return (
                        <Grid item key={index} xs={12} sm={6} md={4} lg={4}>
                            <Card
                            className={classes.root}
                            style={{  height: "100%", borderRadius:"20px"}}
                            >
                            {(!bucket || bucket.stock_list === null) &&
                                <CardHeader className={classes.bucketTitle} classes={{ title: classes.bucketTitle }}
                                        title={
                                            <>
                                            <Link 
                                                color="textPrimary"
                                                href={'dash/' + bucket.slug}
                                                className={classes.link}
                                                style={{ textDecoration: 'none' }}
                                            >
                                            {bucket.name.substr(0, 50)}
                                            </Link>
                                            </>
                                        }
                                        subheader="Add Stocks to get started!"
                                        action={
                                            <>
                                            <IconButton 
                                                style={{padding:0, marginTop:10}}
                                                onClick={handleClick(index)}
                                                aria-label="settings">
                                                <MoreVertIcon />
                                            </IconButton>
                                                <Menu
                                                    id="simple-menu"
                                                    anchorEl={anchorEl}
                                                    keepMounted
                                                    open={Boolean(anchorEl) && index === currentIndex}
                                                    onClose={handleClose}
                                                    style={{boxShadow: 'none'}}
                                                    elevation={0}
                                                >
                                                    <MenuItem onClick={handleClickDeleteOpen}>Edit </MenuItem>
                                                    <MenuItem onClick={setOpenEditPopUp(true)}>Delete</MenuItem>
                                                </Menu>
                                            </>
                                        }
                            />}
                            {bucket && bucket.stock_list != null &&
                                <CardHeader className="cardHeaderBucket" 
                                    title={
                                        <>
                                        <Link 
                                            color="textPrimary"
                                            href={'dash/' + bucket.slug}
                                            className={classes.link}
                                            style={{ textDecoration: 'none', color: "white", margin:0 }}
                                        >
                                            {bucket.name.substr(0, 50)}
                                        </Link>
                                        </>}
                                    action={
                                        <>
                                            <IconButton
                                                style={{padding:0}}
                                             onClick={handleClick(index)}
                                            aria-label="settings">
                                                <MoreVertIcon />
                                            </IconButton>
                                            <Menu
                                                id="simple-menu"
                                                anchorEl={anchorEl}
                                                keepMounted
                                                open={Boolean(anchorEl) && index === currentIndex}
                                                onClose={handleClose}
                                            >
                                                <MenuItem onClick={function(event){ handleClickEditOpen(); handleClose()}}>Edit</MenuItem>
                                                <MenuItem onClick={function(event){ handleClickDeleteOpen(bucket.name, bucket.id); handleClose()}}>Delete </MenuItem>
                                            </Menu>
                                        </>
                                    }
                                    style={{margin:0, textIndent:0}}
                                />}
                                
                                <CardContent className="cardContentBucket">
                                    {(!bucket || bucket.bucket_pos_neg === null) &&
                                    <p style={{ textAlign: "center" }} >
                                        Your Bucket is empty...
                                    </p>}
                                    {bucket && bucket.bucket_pos_neg != null &&
                                    <div className={classes.bucketText}>
                                    <Grid container>
                                        <Grid item xs={12} style={{marginTop:10}}>  
                                            {bucket.bucket_sectors.slice(0, 3)
                                            .sort((a, b) => a.count > b.count)
                                                    .map((stock, index) =>
                                                    {return(
                                                        <Chip key={index} label={stock.sector} size="small" className="stockChips" />
                                                    )}
                                                )}
                                                <>
                                                    {(bucket.bucket_sectors.length > 3) &&
                                                    <Chip key={index} label={bucket.bucket_sectors.length - 3 +"+ more" } size="small" className="stockChips" />
                                                    }
                                                </>
                                
                                            </Grid>
                                        <Grid item>
                                        <Grid item xs={12} sm={12}> 
                                            <Typography variant="overline" color="textSecondary">
                                                {"Total Stocks: " + bucket.stock_count}
                                            </Typography>
                                        </Grid>
                                        <Typography variant="overline"  color="textSecondary">
                                            Return Donut                
                                        </Typography>
                                        </Grid>
                                        <BucketDoughnutDisplay data={bucket.bucket_pos_neg} />
                                        </Grid>
                                    </div>
                                            }   
                                </CardContent>                              
                            </Card>
                        </Grid>                 
                        );                              
                    })}
                </Grid>
            </Container>
            <DeleteBucketPopUp open={openDeletePopUp} handleClose={handleDeleteClose} bucket={bucketName} id={bucketId}/>
        </React.Fragment>
    );
};

上述任何一个组件中是否有一些不寻常的东西会导致红人无限循环?

2 个答案:

答案 0 :(得分:1)

据我所知:-

<MenuItem onClick={setOpenEditPopUp(true)}>Delete</MenuItem>

应该

<MenuItem onClick={handleClickEditOpen}>Delete</MenuItem>

说明:在每次渲染时都会调用 setOpenEditPopUp(true),而不是像您预期的那样将其绑定为事件处理程序。由于您已经声明了 handleClickEditOpen,因此在这里重用它是有意义的。

答案 1 :(得分:0)

错误可能在您代码的以下部分:

 <IconButton 
      style={{padding:0, marginTop:10}}
      onClick={handleClick(index)}
      aria-label="settings">
  <MoreVertIcon />
</IconButton>

您的 onClick 函数一直在执行,这就是导致重新渲染的原因。 相反,您需要将其作为回调传递,因此它只会在用户单击按钮时执行:

  <IconButton 
          style={{padding:0, marginTop:10}}
          onClick={(index) => handleClick(index)}
          aria-label="settings">
      <MoreVertIcon />
    </IconButton>

代码的其他部分不断调用该函数,如下所示:

 <MenuItem onClick={setOpenEditPopUp(true)}>Delete</MenuItem>

所以记得用回调替换它们。