useWatch / useWatchEffect

Watch store changes and perform side effects without triggering re-renders

useWatch

useWatch is a React hook that allows you to subscribe the state changes of a store.

It's similar to useStoreValue, but it will NOT trigger the component re-render when the state changes.

It's useful when you want to do something when the state changes, but you don't want to re-render the component.

For example, you can use it to log the state changes.

useWatch(
  () => counterStore.value.count,
  (current, prev) => {
    console.log("count changed", current, prev);
  }
);

By default, it will trigger the effect when the state changes.

immediate

If you want to trigger the effect immediately, you can use immediate: true option.

useWatch(
  () => counterStore.value.count,
  (current, prev) => {
    console.log("Immediate", current, prev);
  },
  { immediate: true }
);

once

If you want to trigger the effect only once, you can use once: true option.

useWatch(
  () => counterStore.value.count,
  (current, prev) => {
    console.log("Only run once", current, prev);
  },
  { once: true }
);

cleanup

You can also return a function to clean up the effect. It's useful when you want to clean up the effect when the component unmounts or before the next effect runs.

useWatch(
  () => counterStore.value.count,
  (current, prev) => {
    if (current > 10) {
      const handleClick = () => {
        console.log("Current count", counterStore.value.count);
      };
      window.addEventListener("click", handleClick);
      return () => {
        window.removeEventListener("click", handleClick);
      };
    }
  }
);

multiple stores

You can also watch multiple stores at the same time.

useWatch(
  () => [counterStore.value, userStore.value] as const, // ✅ use `as const` to infer the type
  ([counter, user]) => {
    console.log("counter and user changed", counter.count, user.name);
  }
);

Note:

  • If you want to watch an array of stores, you can use [x, y, z] as const to infer the type.

useWatchEffect

useWatchEffect is similar to useWatch, but the effect runs immediately when building the component.

It will auto collect the dependencies and trigger the effect when the dependencies change.

useWatchEffect(() => {
  if (counterStore.value.count > 10) {
    console.log("count is greater than 10");
  }
});

And also supports cleanup function.

useWatchEffect(() => {
  if (counterStore.value.count > 10) {
    const handleClick = () => {
      console.log("Current count", counterStore.value.count);
    };
    window.addEventListener("click", handleClick);
    return () => {
      window.removeEventListener("click", handleClick);
    };
  }
});