什么是 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><divref={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 }}><Inputplaceholder="输入内容(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 }}><Inputplaceholder="输入内容(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><ButtononClick={() => 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 }}><divref={divRef}style={{backgroundColor: "#1890ff",transition: "all 0.3s",}}/><p><strong>配置:</strong> {JSON.stringify(config)}</p></div><div><ButtononClick={() => 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 | 定时器 | 创建定时器 |
useRafInterval | RAF 定时器 | 使用 requestAnimationFrame 创建定时器 |
useTimeout | 延时器 | 创建延时器 |
useRafTimeout | RAF 延时器 | 使用 requestAnimationFrame 创建延时器 |
useLockFn | 锁函数 | 创建锁函数,防止重复执行 |
useUpdate | 强制更新 | 强制组件重新渲染 |
React强大且灵活hooks库——ahooks入门实践之副作用类hook(effect)详解 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿动态资讯