【问题标题】:Why is my setState in a setTimeout in a useEffect not updating my state?为什么我在 useEffect 中的 setTimeout 中的 setState 没有更新我的状态?
【发布时间】:2022-01-28 12:12:29
【问题描述】:

我有一个反应组件,我想在其中存储一个状态的 div 的宽度。我正在使用以下代码(从我的项目中提取):

const Test = (): JSX.Element => {
    const ref = useRef<HTMLDivElement>(null);

    const [width, setWidth] = useState(123);

    useEffect(() => {
        setTimeout(() => {
            const width = ref.current?.clientWidth || 321;
            setWidth(() => width);
        }, 1000);
        setTimeout(() => {
            console.error(width);
        }, 2000);
    }, []);

    ...

    return (
        <div ref={ref}>Test</div>
    );
}

运行它时,在控制台中我看到打印的值123(宽度的原始值)而不是实际宽度或321

我确信我在做一些愚蠢的事情,但我已经盯着这段代码看了很长时间了。所以,希望有人能帮忙!

(我使用setTimeout 的原因是我在某个地方读到过,如果你马上得到ref.current.clientWidth,有时你不会得到正确的值。

【问题讨论】:

标签: typescript react-hooks timeout use-effect use-state


【解决方案1】:

您的方法存在一些问题。

通常最好避免使用setTimeout 来等待组件渲染等动态变化。充其量,它会增加不必要的等待时间,从而使您的应用程序变得异常缓慢;并且有可能你正在等待的任何东西在 timeOut 结束时仍然没有准备好,这是 bug 的来源。

在这种情况下,您实际上并不想等待 1 秒;你想等到div 被渲染,你的代码应该反映它。

This link 详细说明了 React 推荐的问题的解决方案,包括为什么在这种情况下 useCallback 实际上比 useRef 更好。应用于您的示例,它应该如下所示:

const Test = (): JSX.Element => {
  const [width, setWidth] = useState(0);

  const ref = useCallback(node => {
    if (node !== null) {
      setWidth(node.getBoundingClientRect().width);
    }
  }, []);

    ...

    return (
        <div ref={ref}>Test</div>
    );
}

【讨论】:

  • 嗨@Pierre Lejay:谢谢您的回复。真的很有帮助。还有一个问题:设置的宽度不正确。在我的情况下,它设置为 1488(当我将它记录到控制台时),而它应该是 1404!知道为什么吗?
猜你喜欢
  • 1970-01-01
  • 2022-11-15
  • 2022-01-16
  • 1970-01-01
  • 2020-07-31
  • 2019-03-28
  • 2017-01-25
  • 1970-01-01
  • 2020-11-20
相关资源
最近更新 更多