useWatchEffect
自动跟踪的响应式副作用,立即运行并自动清理
为什么选择 useWatchEffect?
当你需要响应式副作用,但又不想手动指定依赖项时的完美选择。
可以将其视为"更智能的 useEffect
",它知道自己依赖于哪些 store。
API 参考
语法
useWatchEffect(effect);
参数
effect
: 包含副作用逻辑的函数(可返回清理函数)
返回值
undefined
: 无返回值
示例
简单响应式副作用
const userStore = createStore({
name: "张三",
isOnline: false,
});
function DocumentTitleUpdater() {
useWatchEffect(() => {
// 自动跟踪 userStore 访问
document.title = `${userStore.value.name} - ${
userStore.value.isOnline ? "在线" : "离线"
}`;
});
return <div>标题更新器已激活</div>;
}
无需依赖数组 - ZenBox 自动检测此副作用依赖于 userStore
。
自动保存与清理
const documentStore = createStore({
content: "",
autoSave: true,
saveInterval: 30000,
});
function AutoSaveEffect() {
useWatchEffect(() => {
// 条件逻辑与提前返回
if (!documentStore.value.autoSave) return;
console.log(`设置自动保存,间隔 ${documentStore.value.saveInterval}ms`);
const interval = setInterval(() => {
console.log("自动保存内容...");
api.saveDocument(documentStore.value.content);
}, documentStore.value.saveInterval);
// 清理函数在下次副作用运行前或卸载时自动执行
return () => {
console.log("清理自动保存间隔");
clearInterval(interval);
};
});
return <div>自动保存管理器已激活</div>;
}
智能依赖跟踪:当 autoSave
、saveInterval
或 content
变化时,副作用会自动重新运行。
分析跟踪器
const analyticsStore = createStore({
userId: null,
sessionId: null,
pageViews: 0,
events: [],
});
function AnalyticsTracker() {
useWatchEffect(() => {
const { userId, sessionId, pageViews } = analyticsStore.value;
if (!userId || !sessionId) return;
// 跟踪页面访问计数
if (pageViews > 0) {
analytics.track("page_view_count", {
userId,
sessionId,
count: pageViews,
timestamp: Date.now(),
});
}
// 设置用户标识
analytics.identify(userId, {
sessionId,
lastActive: Date.now(),
});
console.log(
`分析: 跟踪用户 ${userId}, 会话 ${sessionId}, ${pageViews} 次访问`
);
});
return null;
}
useWatchEffect vs useWatch
特性 | useWatchEffect | useWatch |
---|---|---|
依赖跟踪 | ✅ 自动 | ❌ 手动 |
初始执行 | ✅ 立即 | ❌ 默认仅在变化时 |
配置 | ✅ 零配置 | ⚠️ 需要源参数 |
最适用于 | 一般副作用 | 特定数据监听 |
useWatchEffect - 当需要"响应式 useEffect"时:
// 自动依赖跟踪
useWatchEffect(() => {
if (userStore.value.isLoggedIn) {
initializeUserSession(userStore.value.id);
}
});
useWatch - 当需要精确控制时:
// 手动依赖指定
useWatch(
() => userStore.value.loginAttempts,
(attempts) => {
if (attempts > 3) {
lockAccount();
}
}
);
最佳实践
✅ 保持副作用专注和纯净
// Good:单一职责
useWatchEffect(() => {
document.title = `${appStore.value.title} - MyApp`;
});
✅ 使用提前返回处理条件逻辑
// Good:清晰的条件逻辑
useWatchEffect(() => {
if (!settingsStore.value.enableNotifications) return;
setupNotificationService();
return () => teardownNotificationService();
});
✅ 始终为资源返回清理函数
// Good:正确的资源管理
useWatchEffect(() => {
const timer = setInterval(updateClock, 1000);
return () => clearInterval(timer);
});
❌ 不要在副作用内修改响应式状态
// Bad:创建无限循环
useWatchEffect(() => {
const count = counterStore.value.count;
counterStore.setState((state) => {
state.count = count + 1; // 这会再次触发副作用,导致无限循环
});
});
❌ 不要用于组件渲染状态
// Bad:不必要的间接状态
const [localState, setLocalState] = useState("");
useWatchEffect(() => {
setLocalState(store.value.data); // 应该使用 useStoreValue 替代
});
Hook 比较
Hook | 依赖跟踪 | 立即执行 | 重新渲染 | 使用场景 |
---|---|---|---|---|
useWatchEffect | ✅ 自动 | ✅ 是 | ❌ 否 | 一般响应式副作用 |
useWatch | ❌ 手动 | ❌ 否 | ❌ 否 | 特定数据监听 |
useEffect | ❌ 手动依赖 | ✅ 是 | ❌ 否 | React 特定副作用 |
useStoreValue | ❌ 手动 | ✅ 是 | ✅ 是 | 组件状态同步 |
相关 Hook
useWatch
- 监听状态变化并执行副作用useStoreValue
- 同步 store 最新状态useComputed
- 响应式更新的计算值