Hi I am new to react and unfortunately I get an infinite loop with this code, and am not sure why. This is the code in question:
if (projectInfo) {
console.log('Length is', projectInfo.length);
for (let i = 0; i < projectInfo.length; i++) {
setValues({ ...values, fromDates: projectInfo[i].fromDate });
console.log('i is', i);
}
}
The whole component is here:
import React from 'react';
import Grid from '@material-ui/core/Grid';
import Box from '@material-ui/core/Box';
import Map from '../../shared/components/Map/Map';
export default function FieldworkInofrmation(props) {
const projectInfo = props.props.fieldwork;
const [values, setValues] = React.useState({
fromDates: ' ',
});
if (projectInfo) {
console.log('Length is', projectInfo.length);
for (let i = 0; i < projectInfo.length; i++) {
setValues({ ...values, fromDates: projectInfo[i].fromDate });
console.log('i is', i);
}
}
return (
<Grid container spacing={3}>
<Grid item xs={12}>
<Box fontWeight="fontWeightBold" m={1}>
Fieldwork Information
</Box>
</Grid>
<Grid item xs={12}>
<Box fontWeight="fontWeightLight" m={1}>
Click on map point to view details for the point
</Box>
</Grid>
<Grid item xs={12}>
<Map />
</Grid>
<Grid item xs={1}>
<Box fontWeight="fontWeightLight" m={1}>
Type:
</Box>
</Grid>
<Grid item xs={1}>
<Box fontWeight="fontWeightLight" m={1}>
Period:
</Box>
</Grid>
<Grid item xs={1}>
<Box fontWeight="fontWeightLight" m={1}>
From:
</Box>
</Grid>
<Grid item xs={1}>
<Box fontWeight="fontWeightLight" m={1}>
To:
</Box>
</Grid>
<Grid item xs={6}>
<Box fontWeight="fontWeightLight" m={1}>
Coordinates:
</Box>
</Grid>
<Grid item xs={1}>
<Box fontWeight="fontWeightLight" m={1}>
Station:
</Box>
</Grid>
<Grid item xs={1}>
<Box fontWeight="fontWeightLight" m={1}>
Location:
</Box>
</Grid>
</Grid>
);
}
I tried inserting "i++" at the end of the for-looop but still got the error: "Too many re-renders. React limits the number of renders to prevent an infinite loop". What could I do to solve this?
As others have mentioned, the reason you're getting an infinite loop is because you're updating the state during rendering, which causes a re-render, which updates the state again, and so on.
Since all you're trying to do is effectively set the initial state, there is no need to use the "setState" method (or in your case "setValues").
Simply do the following:
const projectInfo = props.props.fieldwork;
const initialValues = {
fromDates: ' ',
};
if (projectInfo) {
for (let i = 0; i < projectInfo.length; i++) {
initialValues = { ...initialValues, fromDates: projectInfo[i].fromDate };
}
}
const [values, setValues] = React.useState(initialValues);
However, in your current implementation you're constantly overriding the value of "fromDates". I suspect that values
should be an array of objects, each with its own "fromDates" field. For instance:
const projectInfo = props.props.fieldwork;
const initialValues = [{
fromDates: ' ',
}] // this is now an array
if (projectInfo) {
for (let i = 0; i < projectInfo.length; i++) {
initialValues.push({ fromDates: projectInfo[i].fromDate });
}
}
const [values, setValues] = React.useState(initialValues); // `values` will now have an array of objects [{ fromDate: ' ' }, { fromDate: 'Oct 14th, 2019' }, ...]
Lastly, if your intention is indeed to override "fromDate" and all you care about is the latest value, there is no need for a loop at all. Simply set the latest value in the projectInfo
array:
const projectInfo = props.props.fieldwork;
const initialValues = {
fromDates: ' ',
};
if (projectInfo) {
initialValues.fromDates = projectInfo[projectInfo.length -1].fromDates;
}
const [values, setValues] = React.useState(initialValues);
The last solution was also mentioned by @Ghojzilla in the comments.