监控 store 内容变化

对于 store 中内容的变化的监控,Valtio 并没有限定必须在 React 组件中进行。而是在 React 组件内外都可以进行,不管在什么位置监控 store 内容的变化,都是使用 Valtio 提供的 subscribe 函数来完成的。

subscribe 函数的使用非常简单,只需要提供一个需要监控的被代理对象和一个被监控对象发生变化的时候需要执行的回调函数即可。subscribe 函数在执行以后会返回一个 unsubscribe 函数供解除订阅使用。例如以下代码即订阅了 store 的变化,并在其发生变化的时候输出其当前内容。

import { proxy, subscribe } from "valtio";

const store = proxy({
  count: 0,
});

const unsubscribe = subscribe(store, (v) => {
  console.log("store changed:", v);
});

store.count += 1;
store.count += 2;

unsubscribe();

因为 Valtio 会将被代理对象中的嵌套内容也进行代理,所以 subscribe 函数除了可以监控使用 proxy 函数创建的被代理对象以外,还可以监控被代理对象中的嵌套内容。

Caution

在使用 subscribe 函数订阅一个 store 的变化以后,一定要注意在合适的位置调用其返回的 unsubscribe 函数,以避免内存泄漏。

同时监控多个 store

subscribe 函数每次只能定义针对一个被代理对象的监控订阅。如果需要同时监控多个 store 的变化,那么使用 subscribe 就显得非常繁琐了。Valtio 在 valtio/utils 包中提供了一个 watch方法,这个方法可以同时监控任意多个 store 的变化。

watch 函数只接受一个函数作为参数,这个函数拥有一个具名参数:get。这个 get 参数是一个函数,可以通过调用 get 来将要被监控的 store 对象加入 watch 的监控列表中。同时,调用 get 以后,它会返回其参数中 store 的内容。

例如上一节中的 subscribe 使用 watch 来编写就是以下形式的。

import { watch } from "valtio/utils";

watch((get) => {
  const state = get(store);
  console.log("store changed:", state);
});

watch 函数的使用通常要比 subscribe 函数要灵活许多,建议在实际项目中有需要时可优先考虑使用。

wathc 函数同样也有其清理机制,但是并不像 subscribe 一样是返回一个清理函数,而是像 React 中的 useEffect 一样,在其中的回调函数中通过返回一个函数来实现清理。

在一般情况下,watch 函数对于被监控内容的变化是优化过的,如果连续变更被监控 store 中的内容,watch 仅会在 store 最后一次变更以后执行一次回调函数。如果需要 watch 在被监控的 store 每次发生变化的时候都执行回调函数,那么可以为 watch 函数附加一个内容为 {sync: ture} 的参数。

监控 store 中某一个属性的变化

例如当前有一个 store 如下:

const store = proxy({
  count: 0,
  content: "greetings",
});

如果现在只需要监控其中 count 属性的变化,在使用 subscribe 函数的时候,可以使用 subscribe(store.count, () => {}) 的形式来实现。另外,在 valtio/utils 里还提供了一个 subscribrKey 函数,可以直接指定所需要监控的属性。

所以使用 subscribeKey 函数的时候上面的监控调用可以写成 subscribeKey(store, "count", () => {})