yung peso
yung peso

Reputation: 1796

React - Error: Too many re-renders. React limits the number of renders to prevent an infinite loop

Been stuck on this error: Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. After debugging, I think I found the last culprit. It was to do with the next following components. However I don't know why they are causing render issues.

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} />

    );
};

Here is the child: This is a loading component that basically shows a loading indicator, when the loading is done, then it displays the original 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;

Here is the component it loads. I'm pretty sure the error is somewhere here. However I cant find it?

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>
    );
};

Is there something out of the ordinary in any of the components above that would cause infinite loop of redners?

Upvotes: 0

Views: 88

Answers (2)

Rodrigo V
Rodrigo V

Reputation: 514

The error is probably in the following part of your code:

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

Your onClick function is constantly being executed, and that is what´s the causing the re-renders. Instead you need to pass it as a callback, so it will only execute when the user click on the button:

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

There are other parts of the code in which the function is being called constantly, like here:

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

So remeber to replace them with callbacks.

Upvotes: 0

Lakshya Thakur
Lakshya Thakur

Reputation: 8316

From what I can infer :-

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

should be

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

Explanation : On each render there is invocation of setOpenEditPopUp(true) rather than binding it as event handler as you expected it to be. Since you already have handleClickEditOpen declared, reusing it here would make sense.

Upvotes: 1

Related Questions