-
-
Notifications
You must be signed in to change notification settings - Fork 255
/
watch.mdx
85 lines (65 loc) · 3.08 KB
/
watch.mdx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
---
title: 'watch'
section: 'API'
subSection: 'Utils'
description: 'watch for changes.'
---
# `watch`
## Subscription via a getter
This utility supports subscribing to multiple proxy objects (unlike `subscribe` which listens to only a single proxy). Proxy objects are subscribed with a `get` function passed to the callback.
Any changes to the proxy object (or its child proxies) will rerun the callback.
Also note the callback will run once immediately when `watch` is called, even if the proxies have not been yet mutated, to establish the initial subscriptions.
```js
import { proxy } from 'valtio'
import { watch } from 'valtio/utils'
const userState = proxy({ user: { name: 'Juuso' } })
const sessionState = proxy({ expired: false })
watch((get) => {
// `get` adds `sessionState` to this callback's watched proxies
get(sessionState)
const expired = sessionState.expired
// Or call it inline
const name = get(userState).user.name
console.log(`${name}'s session is ${expired ? 'expired' : 'valid'}`)
})
// 'Juuso's session is valid'
sessionState.expired = true
// 'Juuso's session is expired'
```
## Cleanup
You may return a cleanup function that runs both:
- Before each re-invocation of the callback (i.e. due to a watched proxy changing)
- When the `watch` itself is stopped (by calling the cleanup function returned by `watch`)
```js
watch((get) => {
const expired = get(sessionState).expired
const name = get(userState).user.name
console.log(`${name}'s session is ${expired ? 'expired' : 'valid'}`)
return () => {
if (expired) {
console.log('Cleaning up')
}
}
})
// Output from 1st immediate invocation of the callbcak
// 'Juuso's session is valid'
// Changing a dependency will invoke the cleanup callback first,
// but the captured `expired` is false, so we only see output from the
// 2nd invocation of the callback.
sessionState.expired = true
// 'Juuso's session is expired'
// Changing a dependency will again invoke the cleanup callback,
// and `expired` is true now, so we output from both our cleanup
// function as well as the 3rd invocation of the callback.
setTimeout(() => {
userState.user.name = 'Anonymous'
}, 200)
// 200ms -> 'Anonymous's session is expired'
// 'Cleaning up' logged
```
## Gotchas
If you remove the setTimeout in the example above, `'Juuso's session is expired'` will become `'Anonymous's session is expired'` and it will be logged twice. Valtio will batch updates by default. You may pass `{sync: true}` as a second argument to `watch` to disable batching.
## No usage tracking
`watch` currently does not implement the usage tracking of `useSnapshot`, so the callback will rerun anytime a watched proxy (or child proxy) has any fields mutated, regardless of the fields accessed within the `callback`'s code.
And the return value of `get` is just the proxy itself, not a snapshot.
This is because `watch` is a vanilla primitive built on top of `subscribe`. It is potentially possible for `watch`, or a new `watch`-like method, to implement usage tracking in the future, see [this discussion](https://github.com/pmndrs/valtio/discussions/640) if interested.