什么是 ahooks?
ahooks 是一个 React Hooks 库,提供了大量实用的自定义 hooks,帮助开发者更高效地构建 React 应用。其中高级类 hooks 是 ahooks 的一个重要分类,专门用于处理一些高级场景,如受控值、事件发射器、性能优化等。
安装 ahooks
npm install ahooks
高级类 hooks 详解
useControllableValue – 受控值
useControllableValue
用于处理受控和非受控组件的值管理。
import React, { useState } from "react";
import { useControllableValue } from "ahooks";
import { Card, Input, Button, Switch } from "antd";
const UseControllableValueExample = () => {
const [controlled, setControlled] = useState(false);
const [value, setValue] = useControllableValue({
value: controlled ? "受控值" : undefined,
defaultValue: "默认值",
onChange: (val) => {
console.log("值变化:", val);
},
});
return (
<Card title="useControllableValue 受控值">
<div style={{ marginBottom: 16 }}>
<p>
<strong>当前值:</strong> {value}
</p>
<p>
<strong>模式:</strong> {controlled ? "受控" : "非受控"}
</p>
</div>
<div style={{ marginBottom: 16 }}>
<Input
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="输入内容"
style={{ marginBottom: 8 }}
/>
<Switch
checked={controlled}
onChange={setControlled}
checkedChildren="受控"
unCheckedChildren="非受控"
/>
</div>
<Button onClick={() => setValue("重置值")}>重置</Button>
</Card>
);
};
useCreation – 创建值
useCreation
用于创建值,类似于 useMemo
,但更稳定。
import React, { useState } from "react";
import { useCreation } from "ahooks";
import { Card, Button } from "antd";
const UseCreationExample = () => {
const [count, setCount] = useState(0);
// 使用 useCreation 创建稳定的对象
const stableObject = useCreation(() => {
return {
id: Math.random(),
timestamp: Date.now(),
};
}, []);
// 使用 useCreation 创建计算值
const expensiveValue = useCreation(() => {
console.log("计算昂贵值");
return count * 2 + 10;
}, [count]);
return (
<Card title="useCreation 创建值">
<div style={{ marginBottom: 16 }}>
<p>
<strong>计数:</strong> {count}
</p>
<p>
<strong>计算值:</strong> {expensiveValue}
</p>
<p>
<strong>稳定对象 ID:</strong> {stableObject.id}
</p>
<p>
<strong>稳定对象时间戳:</strong> {stableObject.timestamp}
</p>
</div>
<Button onClick={() => setCount(count + 1)}>增加计数</Button>
</Card>
);
};
useEventEmitter – 事件发射器
useEventEmitter
用于创建事件发射器,实现组件间通信。
import React, { useRef } from "react";
import { useEventEmitter } from "ahooks";
import { Card, Button, Input } from "antd";
const UseEventEmitterExample = () => {
const eventEmitter = useEventEmitter();
const handleEmit = () => {
eventEmitter.emit();
};
return (
<Card title="useEventEmitter 事件发射器">
<div style={{ marginBottom: 16 }}>
<p>点击按钮发射事件,输入框会自动获得焦点</p>
</div>
<Button onClick={handleEmit} style={{ marginBottom: 16 }}>
发射事件
</Button>
<InputBox eventEmitter={eventEmitter} />
</Card>
);
};
// 输入框组件
const InputBox = ({ eventEmitter }) => {
const inputRef = useRef(null);
eventEmitter.useSubscription(() => {
inputRef.current?.focus();
});
return (
<Input
ref={inputRef}
placeholder="输入框会自动获得焦点"
style={{ width: "100%" }}
/>
);
};
export default UseEventEmitterExample;
useIsomorphicLayoutEffect – 同构布局副作用
useIsomorphicLayoutEffect
在服务端渲染时使用 useEffect
,在客户端使用 useLayoutEffect
。
import React, { useState, useRef } from "react";
import { useIsomorphicLayoutEffect } from "ahooks";
import { Card, Button } from "antd";
const UseIsomorphicLayoutEffectExample = () => {
const [count, setCount] = useState(0);
const ref = useRef(null);
useIsomorphicLayoutEffect(() => {
if (ref.current) {
// 在布局更新前同步执行
ref.current.style.backgroundColor =
count % 2 === 0 ? "#f0f0f0" : "#e6f7ff";
}
}, [count]);
return (
<Card title="useIsomorphicLayoutEffect 同构布局副作用">
<div style={{ marginBottom: 16 }}>
<p>
<strong>计数:</strong> {count}
</p>
</div>
<div
ref={ref}
style={{
padding: 16,
border: "1px solid #d9d9d9",
borderRadius: 4,
transition: "background-color 0.3s",
}}
>
这个div的背景色会在布局更新前同步改变
</div>
<Button onClick={() => setCount(count + 1)} style={{ marginTop: 16 }}>
切换背景色
</Button>
</Card>
);
};
useLatest – 最新值
useLatest
返回一个 ref,始终指向最新的值。
import React, { useState, useEffect } from "react";
import { useLatest } from "ahooks";
import { Card, Button } from "antd";
const UseLatestExample = () => {
const [count, setCount] = useState(0);
const latestCount = useLatest(count);
useEffect(() => {
const timer = setInterval(() => {
console.log("当前值:", count);
console.log("最新值:", latestCount.current);
}, 1000);
return () => clearInterval(timer);
}, []);
return (
<Card title="useLatest 最新值">
<div style={{ marginBottom: 16 }}>
<p>
<strong>当前值:</strong> {count}
</p>
<p>
<strong>最新值引用:</strong> {latestCount.current}
</p>
<p style={{ fontSize: "12px", color: "#666" }}>
每秒在控制台输出当前值和最新值引用
</p>
</div>
<Button onClick={() => setCount(count + 1)}>增加计数</Button>
</Card>
);
};
useMemoizedFn – 记忆化函数
useMemoizedFn
用于创建记忆化的函数,避免不必要的重新渲染。
import React, { useState } from "react";
import { useMemoizedFn } from "ahooks";
import { Card, Button } from "antd";
const UseMemoizedFnExample = () => {
const [count, setCount] = useState(0);
const [renderCount, setRenderCount] = useState(0);
// 使用 useMemoizedFn 创建稳定的函数
const handleClick = useMemoizedFn(() => {
setCount(count + 1);
console.log("点击处理函数执行");
});
// 每次渲染都会创建新函数
const handleClickNormal = () => {
setCount(count + 1);
console.log("普通函数执行");
};
// 强制重新渲染
const forceRender = () => {
setRenderCount(renderCount + 1);
};
return (
<Card title="useMemoizedFn 记忆化函数">
<div style={{ marginBottom: 16 }}>
<p>
<strong>计数:</strong> {count}
</p>
<p>
<strong>渲染次数:</strong> {renderCount}
</p>
</div>
<div style={{ marginBottom: 16 }}>
<Button onClick={handleClick} style={{ marginRight: 8 }}>
记忆化函数
</Button>
<Button onClick={handleClickNormal} style={{ marginRight: 8 }}>
普通函数
</Button>
<Button onClick={forceRender}>强制重新渲染</Button>
</div>
<p style={{ fontSize: "12px", color: "#666" }}>
记忆化函数在重新渲染时保持稳定,普通函数每次都会重新创建
</p>
</Card>
);
};
useReactive – 响应式状态
useReactive
用于创建响应式状态对象。
import React from "react";
import { useReactive } from "ahooks";
import { Card, Button, Input } from "antd";
const UseReactiveExample = () => {
const state = useReactive({
user: {
name: "张三",
age: 25,
},
count: 0,
list: [1, 2, 3],
});
const handleUpdateName = () => {
state.user.name = "李四";
};
const handleUpdateAge = () => {
state.user.age += 1;
};
const handleAddCount = () => {
state.count += 1;
};
const handleAddToList = () => {
state.list.push(state.list.length + 1);
};
return (
<Card title="useReactive 响应式状态">
<div style={{ marginBottom: 16 }}>
<p>
<strong>用户名:</strong> {state.user.name}
</p>
<p>
<strong>年龄:</strong> {state.user.age}
</p>
<p>
<strong>计数:</strong> {state.count}
</p>
<p>
<strong>列表:</strong> {state.list.join(", ")}
</p>
</div>
<div style={{ marginBottom: 16 }}>
<Input
value={state.user.name}
onChange={(e) => (state.user.name = e.target.value)}
placeholder="输入用户名"
style={{ marginBottom: 8 }}
/>
</div>
<div>
<Button onClick={handleUpdateName} style={{ marginRight: 8 }}>
更新姓名
</Button>
<Button onClick={handleUpdateAge} style={{ marginRight: 8 }}>
增加年龄
</Button>
<Button onClick={handleAddCount} style={{ marginRight: 8 }}>
增加计数
</Button>
<Button onClick={handleAddToList}>添加列表项</Button>
</div>
</Card>
);
};
高级类 hooks 速查表
Hook 名称 | 用途 | 描述 |
---|---|---|
useControllableValue | 受控值 | 处理受控和非受控组件的值管理 |
useCreation | 创建值 | 创建稳定的值,类似于 useMemo |
useEventEmitter | 事件发射器 | 创建事件发射器,实现组件间通信 |
useIsomorphicLayoutEffect | 同构布局副作用 | 在服务端和客户端使用不同的副作用 |
useLatest | 最新值 | 返回一个始终指向最新值的 ref |
useMemoizedFn | 记忆化函数 | 创建记忆化的函数,避免不必要的重新渲染 |
useReactive | 响应式状态 | 创建响应式状态对象 |
原文链接:https://code.ifrontend.net/archives/791,转载请注明出处。
评论0