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); // 应该使用 useStore 替代
});Hook 比较
| Hook | 依赖跟踪 | 立即执行 | 重新渲染 | 使用场景 | 
|---|---|---|---|---|
useWatchEffect | ✅ 自动 | ✅ 是 | ❌ 否 | 一般响应式副作用 | 
useWatch | ❌ 手动 | ❌ 否 | ❌ 否 | 特定数据监听 | 
useEffect | ❌ 手动依赖 | ✅ 是 | ❌ 否 | React 特定副作用 | 
useStore | ❌ 手动 | ✅ 是 | ✅ 是 | 组件状态同步 | 
相关 Hook
useWatch- 监听状态变化并执行副作用useStore- 同步 store 最新状态useComputed- 响应式更新的计算值