React useEffect 警告:超出最大更新深度。有没有解决的办法?

Pet*_*teG 4 javascript reactjs react-hooks

如下面的代码所示,我使用 useEffect 挂钩来监视百分比变量的更改,然后设置一个计时器以在 1 秒内递增该变量。页面加载后回调就会发生,从而启动该过程。

百分比变量用于呈现折线图,该折线图会递增直至达到传递的值。(它基本上显示了通过率百分比,但在加载时,条形图将在屏幕上移动至其百分比。)

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

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

有没有一种方法可以告诉 React 这不会是一个无限循环并让错误消失?或者我需要不同的方法吗?

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;
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助

fho*_*ste 5

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

timer = setTimeout(() => setPercent(newPercent), 1000);
Run Code Online (Sandbox Code Playgroud)

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

const timer = React.useRef()
Run Code Online (Sandbox Code Playgroud)

使用/设置值是对current属性完成的

timer.current = ...
Run Code Online (Sandbox Code Playgroud)

工作示例:

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;
Run Code Online (Sandbox Code Playgroud)