反应useEffect警告:超出最大更新深度。有办法解决吗?

时间:2020-01-17 12:14:48

标签: javascript reactjs react-hooks

如下面的代码所示,我正在使用useEffect挂钩来监视对百分比变量的更改,然后设置一个计时器以在1秒内递增该变量。页面加载后,就会立即执行回调。

percent变量用于呈现折线图,该折线图将递增,直到达到传递的值为止。 (它基本上显示了合格率%,但是在加载时,条形图将在屏幕上移动到其%。)

一切正常,但是控制台标记最大更新深度警告,指出当我在useEffect中使用setState时,它试图防止无限循环。我明白了这一点,但我知道我永远不会传递大于100的值,因此永远不会出现无限循环。我还需要递归功能,以使图表显示为动态填充。

即使我决定忽略警告,但如果我安装组件,也会在测试中产生错误。

有没有一种方法可以告诉我这不是一个无限循环,并且可以消除错误?还是我需要其他方法?

const ReportProgressSummary = ({result, title}) => {
    const [percent, setPercent] = useState(0);
    let timer = null;

    useEffect( () => {
        let newPercent = percent + 1;
        if (newPercent > result) {
            clearTimeout(timer);
            return;
        }
        timer = setTimeout(setPercent(newPercent), 1000);
    }, [percent]);

    return (

        <ContainerStyled>
            <ChartContainerStyled>
                <ChartTitleStyled>{title}</ChartTitleStyled>
                <CheckboxStyled type="checkbox" />
            </ChartContainerStyled>
            <ChartContainerStyled>
                <LineContainerStyled>
                    <Line trailWidth="2" trailColor="red" strokeWidth="4" strokeColor="green" percent={percent}/>
                </LineContainerStyled>
                <h6>{percent}%</h6>
            </ChartContainerStyled>
        </ContainerStyled>
    )
};

export default ReportProgressSummary;

感谢您的帮助

1 个答案:

答案 0 :(得分:4)

timer = setTimeout(setPercent(newPercent), 1000);setPercent(newPercent)将立即被调用。 setTimeout需要一个函数(而不是函数调用):

timer = setTimeout(() => setPercent(newPercent), 1000);

要记住的另一件事是,timer将在每个渲染器上定义,因此clearTimeout不会有任何效果。为避免这种情况,您可以创建一个ref以便记住该值。像这样:

const timer = React.useRef()

使用/设置值已完成current属性

timer.current = ...

工作示例:

const ReportProgressSummary = ({result, title}) => {
    const [percent, setPercent] = useState(0);
    const timer = React.useRef();

    useEffect( () => {
        let newPercent = percent + 1;
        if (newPercent > result) {
            clearTimeout(timer.current);
            return;
        }
        timer.current = setTimeout(() => setPercent(newPercent), 1000);
    }, [percent]);

    return (

        <ContainerStyled>
            <ChartContainerStyled>
                <ChartTitleStyled>{title}</ChartTitleStyled>
                <CheckboxStyled type="checkbox" />
            </ChartContainerStyled>
            <ChartContainerStyled>
                <LineContainerStyled>
                    <Line trailWidth="2" trailColor="red" strokeWidth="4" strokeColor="green" percent={percent}/>
                </LineContainerStyled>
                <h6>{percent}%</h6>
            </ChartContainerStyled>
        </ContainerStyled>
    )
};

export default ReportProgressSummary;