useWatch
在响应式数据变化时执行副作用,不会触发组件重新渲染
API 参考
语法
const currentValue = useWatch(watchSource, callback, options?)参数
watchSource: 要监听的 store 实例、计算函数或源数组callback: 监听数据变化时执行的函数(可返回清理函数)options(可选):immediate: 立即使用当前值执行回调(默认:false)once: 仅执行一次回调,然后停止监听(默认:false)deep: 启用深度比较以处理嵌套对象(默认:false)
返回值
currentValue: 监听源的最新状态值
配置选项
立即执行
useWatch(
  () => userStore.value.preferences,
  (preferences) => {
    applyUserPreferences(preferences);
  },
  { immediate: true } // 构建组件时立即执行回调
);只执行一次
useWatch(
  () => userStore.value.isLoggedIn,
  (isLoggedIn) => {
    if (isLoggedIn) {
      console.log("检测到首次登录!");
      showWelcomeMessage();
    }
  },
  { once: true } // 仅触发一次
);深度比较
const configStore = createStore({
  api: {
    endpoints: { users: "/api/users", orders: "/api/orders" },
    timeout: 5000,
  },
});
useWatch(
  () => configStore.value.api,
  (apiConfig, prevApiConfig) => {
    console.log("API 配置已更改");
    reinitializeApiClient(apiConfig);
  },
  { deep: true } // 深度比较,以避免不必要的副作用执行
);示例
监听 Store 变化
跟踪 store 变化用于日志、分析或外部 API 调用:
const counterStore = createStore({ count: 0 });
function Counter() {
  // 仅监听变化,不触发重新渲染
  useWatch(counterStore, (current, prev) => {
    console.log(`计数: ${prev.count} → ${current.count}`);
    // 跟踪分析,比如埋点
    analytics.track("counter_changed", {
      from: prev.count,
      to: current.count,
    });
  });
  return (
    <button
      onClick={() =>
        counterStore.setState((s) => {
          s.count++;
        })
      }
    >
      增加
    </button>
  );
}监听计算值
监控计算值的业务逻辑:
const userStore = createStore({
  firstName: "张",
  lastName: "三",
  age: 30,
});
function UserTracker() {
  // 监听全名变化
  useWatch(
    () => `${userStore.value.firstName}${userStore.value.lastName}`,
    (fullName, prevFullName) => {
      if (prevFullName) {
        console.log(`姓名更新: "${prevFullName}" → "${fullName}"`);
        api.updateUserProfile({ fullName });
      }
    }
  );
  // 监听年龄里程碑
  useWatch(
    () => userStore.value.age,
    (age, prevAge) => {
      if (age >= 18 && prevAge < 18) {
        console.log("用户已成年!");
        unlockAdultFeatures();
      }
    }
  );
  return <div>正在跟踪用户变化...</div>;
}监听多个源
同时监听多个 store 的变化:
const userStore = createStore({ name: "张三", role: "user" });
const settingsStore = createStore({ theme: "light", language: "zh" });
function AppWatcher() {
  useWatch(
    () => [userStore.value, settingsStore.value] as const,
    ([user, settings], [prevUser, prevSettings]) => {
      // 基于角色的逻辑
      if (user.role !== prevUser?.role) {
        console.log(`角色变化: ${prevUser?.role} → ${user.role}`);
        redirectBasedOnRole(user.role);
      }
      // 主题持久化
      if (settings.theme !== prevSettings?.theme) {
        console.log(`主题: ${prevSettings?.theme} → ${settings.theme}`);
        document.body.className = settings.theme;
        localStorage.setItem("theme", settings.theme);
      }
    }
  );
  return <div>监控应用状态...</div>;
}清理函数
常用于管理订阅、定时器和外部资源等场景:
function WebSocketManager() {
  useWatch(
    () => userStore.value.connectionId,
    (connectionId, prevConnectionId) => {
      if (!connectionId) return;
      console.log(`连接到: ${connectionId}`);
      const ws = new WebSocket(`ws://api.com/${connectionId}`);
      ws.onopen = () => console.log("已连接");
      ws.onmessage = (event) => handleMessage(event.data);
      ws.onerror = (error) => console.error("WebSocket 错误:", error);
      // 清理函数 - 在下次变化或卸载时自动调用
      return () => {
        console.log(`断开连接: ${connectionId}`);
        ws.close();
      };
    }
  );
  return <div>WebSocket 管理器已激活</div>;
}最佳实践
✅ 仅用于副作用
// Good:外部副作用
useWatch(
  () => store.value.theme,
  (theme) => {
    document.body.className = theme;
    localStorage.setItem("theme", theme);
  }
);❌ 不要用于组件状态
// Bad:不必要的间接状态
const [displayValue, setDisplayValue] = useState("");
useWatch(
  () => store.value.data,
  (data) => {
    setDisplayValue(data); // 应该使用 useStore 替代
  }
);✅ 明确监听指定属性变化
// Good:监听特定属性
useWatch(
  () => userStore.value.email,
  (email) => {
    validateEmail(email);
  }
);❌ 避免监听所有状态
// Bad:任何 store 变化都会触发
useWatch(
  () => largeStore.value,
  (store) => {
    console.log("某些内容变化了"); // 太宽泛了
  }
);✅ 始终清理资源
// Good:正确清理
useWatch(
  () => store.value.intervalMs,
  (ms) => {
    const interval = setInterval(doSomething, ms);
    return () => clearInterval(interval);
  }
);Hook 比较
| Hook | 用途 | 重新渲染 | 自动跟踪 | 最适用于 | 
|---|---|---|---|---|
useWatch | 监听状态变化并执行副作用 | ❌ 否 | ❌ 否 | 特定副作用 | 
useWatchEffect | 自动追踪依赖的响应式副作用 | ❌ 否 | ✅ 是 | 一般副作用 | 
useStore | 同步 store 最新状态 | ✅ 是 | ❌ 否 | UI 状态 | 
useComputed | 响应式更新的计算值 | ✅ 是 | ✅ 是 | 计算数据 | 
相关 Hook
useWatchEffect- 自动跟踪响应式副作用useStore- 同步 store 最新状态useComputed- 响应式更新的计算值