返回

useEffect 防抖失效的终极解决方案:React Hooks 中的优雅防抖技巧

前端

在 useEffect 中使用防抖为何无效?

在 React 中,useEffect() 是一个生命周期钩子,用于在组件渲染后执行某些副作用。防抖是一种常见的技术,用于限制函数在特定时间间隔内只能执行一次。然而,直接在 useEffect() 中调用防抖函数往往会失效,原因如下:

  • useEffect() 在每次渲染后都会执行。 这意味着,每次组件更新时,防抖函数都会被重新创建并执行。这导致了防抖功能失效,因为防抖函数的计时器在每次渲染后都会被重置。
  • useEffect() 是异步执行的。 这意味着,在防抖函数执行之前,组件可能已经更新多次。这导致了防抖功能失效,因为防抖函数可能在组件已经更新多次后才执行。

解决方案:使用 useCallback 和 useRef

为了解决上述问题,我们可以使用 useCallback 和 useRef 这两个 React Hooks。useCallback 用于创建和缓存一个函数,而 useRef 用于创建和维护一个可变引用。

import React, { useEffect, useCallback, useRef } from "react";

const MyComponent = () => {
  const debouncedFunction = useCallback(() => {
    // 防抖逻辑
  }, []);

  const isMounted = useRef(false);

  useEffect(() => {
    isMounted.current = true;

    return () => {
      isMounted.current = false;
    };
  }, []);

  useEffect(() => {
    if (!isMounted.current) {
      return;
    }

    // 防抖函数的调用
    debouncedFunction();
  }, [debouncedFunction]);

  return (
    <div>
      {/* 组件内容 */}
    </div>
  );
};

export default MyComponent;

在这个示例中,我们使用 useCallback 创建并缓存了防抖函数 debouncedFunction。然后,我们在 useEffect() 中使用 useRef 创建了一个可变引用 isMounted,用于判断组件是否已挂载。

在第一个 useEffect() 中,我们设置 isMounted.current 为 true,并在组件卸载时将其设置为 false。这确保了我们在组件卸载后不会调用防抖函数。

在第二个 useEffect() 中,我们检查 isMounted.current 是否为 true。如果不是,则说明组件已卸载,我们直接返回,不执行防抖函数。

如果 isMounted.current 为 true,则说明组件已挂载,我们可以调用防抖函数 debouncedFunction。

总结

通过使用 useCallback 和 useRef,我们成功地解决了 useEffect 中防抖失效的问题。这种方法不仅保证了防抖功能的正常工作,还确保了防抖函数不会在组件卸载后被调用。