如何使通知在 4 秒内出现,但在状态发生变化时避免出现

发布于 2025-01-11 10:19:33 字数 1043 浏览 0 评论 0原文

我想在某些状态无效时 4 秒后显示通知消息。但是,如果在那 4 秒内它发生了变化并且现在有效 - 我想在 setTimeout 中添加条件来检查它。但问题是它仍然使用第一个状态值,而不是更改后的状态值。我修复此问题的假设之一是在同步之前在行中设置 setState,但不知道如何操作。也许还有其他方法可以修复它吗?

useEffect(async () => {
      try {
        const snippetIndexResponse = await getSnippetIndex(
            //some params
        );
        if (snippetIndexResponse !== -1) {
          setSnippetIndex(snippetIndexResponse);
        } else {
          setSnippetIndex(null)
          setTimeout(() => {
            console.log(snippetIndex) <-- it logs only first state, instead wanted null 
            if(!snippetIndex) {
              openNotificationWithIcon(
                  "error",
                  "Invalid snippet selection",
                  "Snippet slice shouldn't tear code blocks. Please, try again."
              );
            }
          }, 4000)
        }
      } catch (err) {
        setSnippetIndex(null);
        openNotificationWithIcon("error", err.name, err.message);
      }
  }, [beginRow, endRow]);

I want to show notification message after 4 seconds when some state is invalid. But if during that 4 seconds it has changed and is valid now - I want to put condition in setTimeout that would check it. But the problem is that it still uses the first state value, not the changed one. One of my assumptions to fix it was making setState in the line before synchronous, but don't know how. Maybe any other ways to fix it?

useEffect(async () => {
      try {
        const snippetIndexResponse = await getSnippetIndex(
            //some params
        );
        if (snippetIndexResponse !== -1) {
          setSnippetIndex(snippetIndexResponse);
        } else {
          setSnippetIndex(null)
          setTimeout(() => {
            console.log(snippetIndex) <-- it logs only first state, instead wanted null 
            if(!snippetIndex) {
              openNotificationWithIcon(
                  "error",
                  "Invalid snippet selection",
                  "Snippet slice shouldn't tear code blocks. Please, try again."
              );
            }
          }, 4000)
        }
      } catch (err) {
        setSnippetIndex(null);
        openNotificationWithIcon("error", err.name, err.message);
      }
  }, [beginRow, endRow]);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

深海夜未眠 2025-01-18 10:19:33

首先,您不能将 useEffect 回调作为异步方法调用。

其次,为了您的目的,您可以执行以下操作:

let timeoutId = null;

useEffect(() => {
  (async () => {
  if (timeoutId) {
    clearTimeout(timeoutId);
  }
try {
        const snippetIndexResponse = await getSnippetIndex(
            //some params
        );
        if (snippetIndexResponse !== -1) {
          setSnippetIndex(snippetIndexResponse);
        } else {
          setSnippetIndex(null)
          timeoutId = setTimeout(() => {
            console.log(snippetIndex) <-- it logs only first state, instead wanted null 
            if(!snippetIndex) {
              openNotificationWithIcon(
                  "error",
                  "Invalid snippet selection",
                  "Snippet slice shouldn't tear code blocks. Please, try again."
              );
            }
          }, 4000)
        }
      } catch (err) {
        setSnippetIndex(null);
        openNotificationWithIcon("error", err.name, err.message);
      }
  })();
      
  }, [beginRow, endRow]);

First You can not call useEffect callback as async method.

Second for your purpose you can act as below:

let timeoutId = null;

useEffect(() => {
  (async () => {
  if (timeoutId) {
    clearTimeout(timeoutId);
  }
try {
        const snippetIndexResponse = await getSnippetIndex(
            //some params
        );
        if (snippetIndexResponse !== -1) {
          setSnippetIndex(snippetIndexResponse);
        } else {
          setSnippetIndex(null)
          timeoutId = setTimeout(() => {
            console.log(snippetIndex) <-- it logs only first state, instead wanted null 
            if(!snippetIndex) {
              openNotificationWithIcon(
                  "error",
                  "Invalid snippet selection",
                  "Snippet slice shouldn't tear code blocks. Please, try again."
              );
            }
          }, 4000)
        }
      } catch (err) {
        setSnippetIndex(null);
        openNotificationWithIcon("error", err.name, err.message);
      }
  })();
      
  }, [beginRow, endRow]);
翻身的咸鱼 2025-01-18 10:19:33

我认为您可以将通知 UI 作为一个组件并将状态作为参数传递。如果状态发生变化,组件将被销毁并重新创建。
您可以在 useEffect() 中添加 4 秒计时器,也可以在 useEffect 的“返回”中取消它。如果计时器触发,则更新一些可见性标志。

实时输入此内容 - 因此可能包含一些语法错误...

cost myAlert = (isLoading) => {
  const [isVisible, setIsVisible] = setIsVisible(false)

  useEffect(()=>{
    const timerId = setTimer, setIsVisible(true) when it goes off
    return ()=>{cancelTimer(timerId)}
  }, [isLoading, setIsVisible])

  if (!isLoading && !isVisible) return null

  if (isVisible) return (
    <> 
      // your ui
    </>
  )
}

您可能想在 setTimer 上使用 useCallback,这样如果 isLoading 更改,它不会导致 useEffect 触发 - 但我认为这应该让您接近解决方案。

I think you could make the notification UI a component and pass the state in as a parameter. If the state changes the component will be destroyed and recreated.
And you can add the 4 second timer in useEffect() as well as cancel it in the 'return' of useEffect. If the timer fires, update some visibility flag.

Live typing this - so may contain some syntax errors...

cost myAlert = (isLoading) => {
  const [isVisible, setIsVisible] = setIsVisible(false)

  useEffect(()=>{
    const timerId = setTimer, setIsVisible(true) when it goes off
    return ()=>{cancelTimer(timerId)}
  }, [isLoading, setIsVisible])

  if (!isLoading && !isVisible) return null

  if (isVisible) return (
    <> 
      // your ui
    </>
  )
}

You may want to useCallback on setTimer so it won't cause useEffect to fire if isLoading changes -- but I think this should get you close to the solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文