当前位置: 首页 > 知识库问答 >
问题:

前端 - react 如何更好地处理下面的代码模式?

长孙瑞
2024-11-10
async function like(cleanups: (() => void)[] ) {
  const a = await delay(2000) // 等待一些异步操作
  if(a) {
    const clearId = setInterval(play, 2000);
    cleanups.push(() => {
      clearInterval(clearId);
    });
  }
}
useEffect(() => {
      const cleanups: (() => void)[] = [];
      like(cleanups);
      function clean() {
        cleanups.forEach((cleanup) => {
          cleanup();
        });
      }
      return clean
  }, [status, interval]); // 删除了部分 status, interval 的依赖逻辑

以上的代码如果在 StrictMode 模式下运行就会发现有一个定时器没有被移除,这也表明其实以上的代码是有问题的。如果依赖项快速变化,那么会有越来越多的定时器没有被移除,原因是 cleanups 的收集是异步的,在没有收集到定时器前,可能 clean 就执行了,导致了之后收集的定时器并没有被移除。如何在保持一样的功能下修复上面的问题?

共有2个答案

索嘉石
2024-11-10

这样可以吗:

async function like(cleanups: (() => void)[]) {
  let a = false;
  const clearId = setInterval(() => a && play(), 2000);
  cleanups.push(() => clearInterval(clearId));

  a = await delay(2000);
}
虞承泽
2024-11-10

可以使用一个 useRef 来存储当前的定时器 ID,并在 useEffect 清理函数中立即清理它。
以下是修复后的代码:

import { useEffect, useRef } from 'react';

async function like(setupCleanup: (cleanup: () => void) => void) {
  const a = await delay(2000); // 等待一些异步操作
  if (a) {
    const clearId = setInterval(play, 2000);
    setupCleanup(() => {
      clearInterval(clearId);
    });
  }
}

useEffect(() => {
  const cleanupRef = useRef<(() => void) | null>(null);

  const setupCleanup = (cleanup: () => void) => {
    if (cleanupRef.current) {
      cleanupRef.current(); // 清理之前的定时器
    }
    cleanupRef.current = cleanup;
  };

  like(setupCleanup);

  return () => {
    if (cleanupRef.current) {
      cleanupRef.current(); // 组件卸载时清理定时器
    }
  };
}, [status, interval]); // 确保 status 和 interval 是定义好的依赖

使用 useRef 来存储当前的清理函数,并在每次 useEffect 执行时立即清理之前的定时器。这确保了即使在依赖项快速变化的情况下,定时器也能被正确清理。这样可以避免定时器泄漏的问题。

 类似资料:
  • 本文向大家介绍你是如何更好地处理Async/Await的异常的?相关面试题,主要包含被问及你是如何更好地处理Async/Await的异常的?时的应答技巧和注意事项,需要的朋友参考一下 @HCLQ 玩node时。。他那么写还是比较常见的。。 你是指 callback 中使用的 error-first 的错误处理方式吗? 这种的确是常见,但是返回 的 我真的没见过。或许可以给些例子?

  • react代码中eslint的错误提示: 这个该改成啥??

  • 我有一小段Java密码。我想用一种更有建设性的方式和更优雅的方式重写下面的代码。我怎样才能实现它? 非常感谢您的帮助

  • API 都搞不好,还怎么当程序员?如果 API 设计只是后台的活,为什么还需要前端工程师。 作为一个程序员,我讨厌那些没有文档的库。我们就好像在操纵一个黑盒一样,预期不了它的正常行为是什么。输入了一个 A,预期返回的是一个 B,结果它什么也没有。有的时候,还抛出了一堆异常,导致你的应用崩溃。 因为交付周期的原因,接入了一个第三方的库,遇到了这么一些问题:文档老旧,并且不够全面。这个问题相比于没有文

  • 我的理解是span的line-height设置为0,那么它所在行的行框的高度就变为0,无法撑起div的高度,因此div的高度因此为0。但实际上,div的高度为27, 应该如何解释div的高度呢? 另外,如果去掉<!DOCTYPE html>,那么div的高度为0,为什么会有这个现象呢? 代码地址:https://jsbin.com/ziyimaleqe/edit?html,output

  • 冲突合并一般是因为自己的本地做的提交和服务器上的提交有差异,并且这些差异中的文件改动,Git不能自动合并,那么就需要用户手动进行合并 如我这边执行git pull origin master 如果Git能够自动合并,那么过程看起来是这样的 拉取的时候,Git自动合并,并产生了一次提交。 如果Git不能够自动合并,那么会提示 这个时候我们就可以知道README.MD有冲突,需要我们手动解决,修改RE

  • 这就是它看起来的样子。 它工作得很好,等待数据加载,然后开始操作。但这是相当多的代码,有没有更好的方法来做它?

  • 我正在创建一个报告,并已经自动化了抓取图像并将其放入的过程。它正在工作,但比它需要的时间要长。我希望有人能帮我实现一个循环来简化代码。 我尝试了几种方法,但当涉及到放置图像的区域时,它似乎总是默认为我设置的初始变量。 DS1=rng&“a.jpg” DS1_1=左(DS1,6)&“00-”&Mid(DS1,4,3)&“99” DS1_2=左(DS1,8) 在错误转到DS3 时,设置shp=acti