所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

React强大且灵活hooks库——ahooks入门实践之副作用类hook(effect)详解

什么是 ahooks?

ahooks 是一个 React Hooks 库,提供了大量实用的自定义 hooks,帮助开发者更高效地构建 React 应用。其中副作用类 hooks 是 ahooks 的一个重要分类,专门用于处理各种副作用操作,如定时器、防抖、节流等。

安装 ahooks

npm install ahooks

副作用类 hooks 详解

useUpdateEffect – 更新时执行副作用

useUpdateEffect 在依赖项更新时执行副作用,跳过首次执行。

import React, { useState } from "react";
import { useUpdateEffect } from "ahooks";
import { Button, Card } from "antd";

const UseUpdateEffectExample = () => {
  const [count, setCount] = useState(0);
  const [updateCount, setUpdateCount] = useState(0);

  useUpdateEffect(() => {
    console.log("依赖项更新,执行副作用");
    setUpdateCount((prev) => prev + 1);
  }, [count]);

  return (
    <Card title="useUpdateEffect 更新时执行副作用">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>计数:</strong> {count}
        </p>
        <p>
          <strong>更新次数:</strong> {updateCount}
        </p>
      </div>

      <Button onClick={() => setCount(count + 1)}>增加计数</Button>
    </Card>
  );
};

useUpdateLayoutEffect – 更新时执行布局副作用

useUpdateLayoutEffect 在依赖项更新时执行布局副作用,跳过首次执行。

import React, { useState, useRef } from "react";
import { useUpdateLayoutEffect } from "ahooks";
import { Button, Card } from "antd";

const UseUpdateLayoutEffectExample = () => {
  const [count, setCount] = useState(0);
  const divRef = useRef(null);

  useUpdateLayoutEffect(() => {
    if (divRef.current) {
      divRef.current.style.backgroundColor =
        count % 2 === 0 ? "#f0f0f0" : "#e6f7ff";
    }
  }, [count]);

  return (
    <Card title="useUpdateLayoutEffect 更新时执行布局副作用">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>计数:</strong> {count}
        </p>
        <div
          ref={divRef}
          style={{
            padding: 16,
            border: "1px solid #d9d9d9",
            borderRadius: 4,
            transition: "background-color 0.3s",
          }}
        >
          这个div的背景色会在计数更新时改变
        </div>
      </div>

      <Button onClick={() => setCount(count + 1)}>切换背景色</Button>
    </Card>
  );
};

useAsyncEffect – 异步副作用

useAsyncEffect 用于处理异步副作用操作。

import React, { useState } from "react";
import { useAsyncEffect } from "ahooks";
import { Button, Card } from "antd";

const UseAsyncEffectExample = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useAsyncEffect(async () => {
    setLoading(true);
    try {
      // 模拟异步请求
      await new Promise((resolve) => setTimeout(resolve, 1000));
      setData("异步数据加载完成");
    } catch (error) {
      setData("加载失败");
    } finally {
      setLoading(false);
    }
  }, []);

  return (
    <Card title="useAsyncEffect 异步副作用">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>状态:</strong> {loading ? "加载中..." : data}
        </p>
      </div>

      <Button disabled={loading}>组件挂载时自动加载数据</Button>
    </Card>
  );
};

useDebounceEffect – 防抖副作用

useDebounceEffect 创建防抖的副作用,延迟执行。

import React, { useState } from "react";
import { useDebounceEffect } from "ahooks";
import { Input, Card } from "antd";

const UseDebounceEffectExample = () => {
  const [value, setValue] = useState("");
  const [debouncedValue, setDebouncedValue] = useState("");

  useDebounceEffect(
    () => {
      setDebouncedValue(value);
      console.log("防抖后的值:", value);
    },
    [value],
    { wait: 500 }
  );

  return (
    <Card title="useDebounceEffect 防抖副作用">
      <div style={{ marginBottom: 16 }}>
        <Input
          placeholder="输入内容(500ms 防抖)"
          value={value}
          onChange={(e) => setValue(e.target.value)}
          style={{ marginBottom: 8 }}
        />
        <p>
          <strong>实时值:</strong> {value}
        </p>
        <p>
          <strong>防抖值:</strong> {debouncedValue}
        </p>
      </div>
    </Card>
  );
};

useDebounceFn – 防抖函数

useDebounceFn 创建防抖函数。

import React, { useState } from "react";
import { useDebounceFn } from "ahooks";
import { Button, Card } from "antd";

const UseDebounceFnExample = () => {
  const [count, setCount] = useState(0);

  const { run } = useDebounceFn(
    () => {
      setCount((prev) => prev + 1);
    },
    { wait: 1000 }
  );

  return (
    <Card title="useDebounceFn 防抖函数">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>计数:</strong> {count}
        </p>
        <p style={{ fontSize: "12px", color: "#666" }}>
          快速点击按钮,只有最后一次点击会在1秒后生效
        </p>
      </div>

      <Button onClick={run}>防抖增加计数</Button>
    </Card>
  );
};

useThrottleFn – 节流函数

useThrottleFn 创建节流函数。

import React, { useState } from "react";
import { useThrottleFn } from "ahooks";
import { Button, Card } from "antd";

const UseThrottleFnExample = () => {
  const [count, setCount] = useState(0);

  const { run } = useThrottleFn(
    () => {
      setCount((prev) => prev + 1);
    },
    { wait: 1000 }
  );

  return (
    <Card title="useThrottleFn 节流函数">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>计数:</strong> {count}
        </p>
        <p style={{ fontSize: "12px", color: "#666" }}>
          快速点击按钮,每秒最多执行一次
        </p>
      </div>

      <Button onClick={run}>节流增加计数</Button>
    </Card>
  );
};

useThrottleEffect – 节流副作用

useThrottleEffect 创建节流的副作用。

import React, { useState } from "react";
import { useThrottleEffect } from "ahooks";
import { Input, Card } from "antd";

const UseThrottleEffectExample = () => {
  const [value, setValue] = useState("");
  const [throttledValue, setThrottledValue] = useState("");

  useThrottleEffect(
    () => {
      setThrottledValue(value);
      console.log("节流后的值:", value);
    },
    [value],
    { wait: 1000 }
  );

  return (
    <Card title="useThrottleEffect 节流副作用">
      <div style={{ marginBottom: 16 }}>
        <Input
          placeholder="输入内容(1000ms 节流)"
          value={value}
          onChange={(e) => setValue(e.target.value)}
          style={{ marginBottom: 8 }}
        />
        <p>
          <strong>实时值:</strong> {value}
        </p>
        <p>
          <strong>节流值:</strong> {throttledValue}
        </p>
      </div>
    </Card>
  );
};

useDeepCompareEffect – 深度比较副作用

useDeepCompareEffect 使用深度比较来决定是否执行副作用。

import React, { useState } from "react";
import { useDeepCompareEffect } from "ahooks";
import { Button, Card } from "antd";

const UseDeepCompareEffectExample = () => {
  const [obj, setObj] = useState({ name: "张三", age: 25 });
  const [count, setCount] = useState(0);

  useDeepCompareEffect(() => {
    console.log("对象深度比较后发生变化:", obj);
    setCount((prev) => prev + 1);
  }, [obj]);

  return (
    <Card title="useDeepCompareEffect 深度比较副作用">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>对象:</strong> {JSON.stringify(obj)}
        </p>
        <p>
          <strong>执行次数:</strong> {count}
        </p>
      </div>

      <div>
        <Button
          onClick={() => setObj({ name: "张三", age: 25 })}
          style={{ marginRight: 8 }}
        >
          设置相同对象(浅比较会触发,深度比较不会)
        </Button>
        <Button onClick={() => setObj({ name: "李四", age: 30 })}>
          设置不同对象
        </Button>
      </div>
    </Card>
  );
};

useDeepCompareLayoutEffect – 深度比较布局副作用

useDeepCompareLayoutEffect 使用深度比较来决定是否执行布局副作用。

import React, { useState, useRef } from "react";
import { useDeepCompareLayoutEffect } from "ahooks";
import { Button, Card } from "antd";

const UseDeepCompareLayoutEffectExample = () => {
  const [config, setConfig] = useState({ width: 100, height: 100 });
  const divRef = useRef(null);

  useDeepCompareLayoutEffect(() => {
    if (divRef.current) {
      divRef.current.style.width = `${config.width}px`;
      divRef.current.style.height = `${config.height}px`;
    }
  }, [config]);

  return (
    <Card title="useDeepCompareLayoutEffect 深度比较布局副作用">
      <div style={{ marginBottom: 16 }}>
        <div
          ref={divRef}
          style={{
            backgroundColor: "#1890ff",
            transition: "all 0.3s",
          }}
        />
        <p>
          <strong>配置:</strong> {JSON.stringify(config)}
        </p>
      </div>

      <div>
        <Button
          onClick={() => setConfig({ width: 100, height: 100 })}
          style={{ marginRight: 8 }}
        >
          设置相同配置
        </Button>
        <Button onClick={() => setConfig({ width: 200, height: 150 })}>
          设置不同配置
        </Button>
      </div>
    </Card>
  );
};

useInterval – 定时器

useInterval 创建定时器。

import React, { useState } from "react";
import { useInterval } from "ahooks";
import { Button, Card } from "antd";

const UseIntervalExample = () => {
  const [count, setCount] = useState(0);
  const [delay, setDelay] = useState(1000);

  useInterval(() => {
    setCount((prev) => prev + 1);
  }, delay);

  return (
    <Card title="useInterval 定时器">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>计数:</strong> {count}
        </p>
        <p>
          <strong>间隔:</strong> {delay}ms
        </p>
      </div>

      <div>
        <Button onClick={() => setDelay(1000)} style={{ marginRight: 8 }}>
          1秒间隔
        </Button>
        <Button onClick={() => setDelay(2000)} style={{ marginRight: 8 }}>
          2秒间隔
        </Button>
        <Button onClick={() => setDelay(null)}>停止</Button>
      </div>
    </Card>
  );
};

useRafInterval – RAF 定时器

useRafInterval 使用 requestAnimationFrame 创建定时器。

import React, { useState } from "react";
import { useRafInterval } from "ahooks";
import { Button, Card } from "antd";

const UseRafIntervalExample = () => {
  const [count, setCount] = useState(0);
  const [delay, setDelay] = useState(1000);

  useRafInterval(() => {
    setCount((prev) => prev + 1);
  }, delay);

  return (
    <Card title="useRafInterval RAF 定时器">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>计数:</strong> {count}
        </p>
        <p>
          <strong>间隔:</strong> {delay}ms
        </p>
        <p style={{ fontSize: "12px", color: "#666" }}>
          使用 requestAnimationFrame,性能更好
        </p>
      </div>

      <div>
        <Button onClick={() => setDelay(1000)} style={{ marginRight: 8 }}>
          1秒间隔
        </Button>
        <Button onClick={() => setDelay(2000)} style={{ marginRight: 8 }}>
          2秒间隔
        </Button>
        <Button onClick={() => setDelay(null)}>停止</Button>
      </div>
    </Card>
  );
};

useTimeout – 延时器

useTimeout 创建延时器。

import React, { useState } from "react";
import { useTimeout } from "ahooks";
import { Button, Card } from "antd";

const UseTimeoutExample = () => {
  const [message, setMessage] = useState("");

  useTimeout(() => {
    setMessage("3秒后显示的消息");
  }, 3000);

  return (
    <Card title="useTimeout 延时器">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>消息:</strong> {message || "等待中..."}
        </p>
      </div>

      <Button disabled>组件挂载3秒后显示消息</Button>
    </Card>
  );
};

useRafTimeout – RAF 延时器

useRafTimeout 使用 requestAnimationFrame 创建延时器。

import React, { useState } from "react";
import { useRafTimeout } from "ahooks";
import { Button, Card } from "antd";

const UseRafTimeoutExample = () => {
  const [message, setMessage] = useState("");

  useRafTimeout(() => {
    setMessage("2秒后显示的消息(RAF)");
  }, 2000);

  return (
    <Card title="useRafTimeout RAF 延时器">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>消息:</strong> {message || "等待中..."}
        </p>
        <p style={{ fontSize: "12px", color: "#666" }}>
          使用 requestAnimationFrame,性能更好
        </p>
      </div>

      <Button disabled>组件挂载2秒后显示消息</Button>
    </Card>
  );
};

useLockFn – 锁函数

useLockFn 创建锁函数,防止重复执行。

import React, { useState } from "react";
import { useLockFn } from "ahooks";
import { Button, Card } from "antd";

const UseLockFnExample = () => {
  const [loading, setLoading] = useState(false);
  const [count, setCount] = useState(0);

  const handleClick = useLockFn(async () => {
    setLoading(true);
    // 模拟异步操作
    await new Promise((resolve) => setTimeout(resolve, 2000));
    setCount((prev) => prev + 1);
    setLoading(false);
  });

  return (
    <Card title="useLockFn 锁函数">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>计数:</strong> {count}
        </p>
        <p>
          <strong>状态:</strong> {loading ? "执行中..." : "空闲"}
        </p>
      </div>

      <Button onClick={handleClick} loading={loading}>
        点击执行(2秒内重复点击无效)
      </Button>
    </Card>
  );
};

useUpdate – 强制更新

useUpdate 强制组件重新渲染。

import React from "react";
import { useUpdate } from "ahooks";
import { Button, Card } from "antd";

const UseUpdateExample = () => {
  const update = useUpdate();

  return (
    <Card title="useUpdate 强制更新">
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>渲染时间:</strong> {new Date().toLocaleTimeString()}
        </p>
      </div>

      <Button onClick={update}>强制重新渲染</Button>
    </Card>
  );
};

副作用类 hooks 速查表

Hook 名称用途描述
useUpdateEffect更新时执行副作用在依赖项更新时执行,跳过首次执行
useUpdateLayoutEffect更新时执行布局副作用在依赖项更新时执行布局副作用
useAsyncEffect异步副作用处理异步副作用操作
useDebounceEffect防抖副作用创建防抖的副作用,延迟执行
useDebounceFn防抖函数创建防抖函数
useThrottleFn节流函数创建节流函数
useThrottleEffect节流副作用创建节流的副作用
useDeepCompareEffect深度比较副作用使用深度比较决定是否执行副作用
useDeepCompareLayoutEffect深度比较布局副作用使用深度比较决定是否执行布局副作用
useInterval定时器创建定时器
useRafIntervalRAF 定时器使用 requestAnimationFrame 创建定时器
useTimeout延时器创建延时器
useRafTimeoutRAF 延时器使用 requestAnimationFrame 创建延时器
useLockFn锁函数创建锁函数,防止重复执行
useUpdate强制更新强制组件重新渲染
资源下载
下载价格免费
注意:本网站资源属于虚拟产品,不支持退款。请谨慎购买! 购买后资源无法下载,请联系客服QQ:844475003,微信号:th844475003。
原文链接:https://code.ifrontend.net/archives/787,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?