【问题标题】:How to prevent infinite loop in react component?如何防止反应组件中的无限循环?
【发布时间】:2019-10-14 11:23:19
【问题描述】:

您好,我是新来的反应,不幸的是我得到了这个代码的无限循环,我不知道为什么。这是有问题的代码:

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++”,但仍然出现错误:“重新渲染过多。React 限制了渲染次数以防止无限循环”。我能做些什么来解决这个问题?

【问题讨论】:

  • 我认为你可以使用useEffect
  • 当你调用setValues() 时,React 将更新组件的状态。这意味着您的 FieldworkInofrmation 函数将再次完整运行。调用setValues()。等等等等,-> 无限循环。将状态更新放入一个函数中,然后将该函数传递给useEffect()。另外,看看你的代码,你为什么还要设置状态?您没有在其他任何地方使用它,并且它不会在您的组件内部发生变化。从外观上看,您只是将道具复制到状态?
  • fromDates 是 values 状态对象的属性。在(应该是什么)循环结束时,它将只有 projectInfo 属性中最后一个元素的值。基本上projectInfo[projectInfo.length - 1].fromDate。我猜这不是你想要的……values.fromDates 假设是一个数组吗?或者可能是具有不同键的对象?如果您让我们知道您要实现的目标(以及 fromDates 的含义),那么回答问题会更容易

标签: javascript reactjs for-loop infinite-loop


【解决方案1】:

正如其他人所提到的,您获得无限循环的原因是因为您在渲染期间更新了状态,这会导致重新渲染,从而再次更新状态,等等。

由于您要做的只是有效地设置初始状态,因此无需使用“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 在 cmets 中也提到了最后一个解决方案。

【讨论】:

    【解决方案2】:

    这很糟糕,状态每次都会更新

    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

    【讨论】:

    • 谢谢!这更好,但我仍然得到同样的错误。我这样做的原因是我从 API 获得了未知数量的对象。它可能是 1、2、3... 等等。所以我试图更新这些值而不知道需要提前更新多少次
    猜你喜欢
    • 2020-01-09
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多