如何防止反应组件中的无限循环?
How to prevent infinite loop in react component?
您好,我是 React 新手,不幸的是我遇到了这段代码的无限循环,我不确定为什么。这是有问题的代码:
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);
}
}
整个组件在这里:
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>
);
}
我尝试在 for 循环的末尾插入 "i++",但仍然出现错误:"Too many re-renders. React limits the number of renders to prevent an infinite loop"。我能做些什么来解决这个问题?
这很糟糕,状态每次都会更新
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);
}
}
这很好,状态更新一次
if (projectInfo) {
console.log('Length is', projectInfo.length);
let newValues = {}
for (let i = 0; i < projectInfo.length; i++) {
newValues = {
...newValues,
...values,
fromDates: projectInfo[i].fromDate
};
console.log('i is', i);
}
setValues(newValues);
}
仍然不确定为什么每次都要覆盖 fromDates
正如其他人所提到的,您获得无限循环的原因是因为您在渲染期间更新状态,这会导致重新渲染,从而再次更新状态,依此类推。
由于您要做的只是有效地设置初始状态,因此无需使用 "setState" 方法(或者在您的情况下 "setValues")。
只需执行以下操作:
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);
但是,在您当前的实现中,您不断地覆盖 "fromDates" 的值。我怀疑 values
应该是一个对象数组,每个对象都有自己的 "fromDates" 字段。例如:
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' }, ...]
最后,如果您的意图确实是覆盖 "fromDate" 并且您关心的只是最新值,则根本不需要循环。只需在 projectInfo
数组中设置最新值:
const projectInfo = props.props.fieldwork;
const initialValues = {
fromDates: ' ',
};
if (projectInfo) {
initialValues.fromDates = projectInfo[projectInfo.length -1].fromDates;
}
const [values, setValues] = React.useState(initialValues);
@Ghojzilla 在评论中也提到了最后一个解决方案。
您好,我是 React 新手,不幸的是我遇到了这段代码的无限循环,我不确定为什么。这是有问题的代码:
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);
}
}
整个组件在这里:
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>
);
}
我尝试在 for 循环的末尾插入 "i++",但仍然出现错误:"Too many re-renders. React limits the number of renders to prevent an infinite loop"。我能做些什么来解决这个问题?
这很糟糕,状态每次都会更新
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);
}
}
这很好,状态更新一次
if (projectInfo) {
console.log('Length is', projectInfo.length);
let newValues = {}
for (let i = 0; i < projectInfo.length; i++) {
newValues = {
...newValues,
...values,
fromDates: projectInfo[i].fromDate
};
console.log('i is', i);
}
setValues(newValues);
}
仍然不确定为什么每次都要覆盖 fromDates
正如其他人所提到的,您获得无限循环的原因是因为您在渲染期间更新状态,这会导致重新渲染,从而再次更新状态,依此类推。
由于您要做的只是有效地设置初始状态,因此无需使用 "setState" 方法(或者在您的情况下 "setValues")。
只需执行以下操作:
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);
但是,在您当前的实现中,您不断地覆盖 "fromDates" 的值。我怀疑 values
应该是一个对象数组,每个对象都有自己的 "fromDates" 字段。例如:
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' }, ...]
最后,如果您的意图确实是覆盖 "fromDate" 并且您关心的只是最新值,则根本不需要循环。只需在 projectInfo
数组中设置最新值:
const projectInfo = props.props.fieldwork;
const initialValues = {
fromDates: ' ',
};
if (projectInfo) {
initialValues.fromDates = projectInfo[projectInfo.length -1].fromDates;
}
const [values, setValues] = React.useState(initialValues);
@Ghojzilla 在评论中也提到了最后一个解决方案。