- Daishi Kato's Read the Code
- Posts
- How Proxies Help State Usage Tracking
How Proxies Help State Usage Tracking
proxy-compare is an Internal Library Used in Valtio
Hi,
Valtio consists of two parts: the vanilla part and the React part. The vanilla part handles write operations, while the React part handles read operations.
For more information, check out these two blog posts I wrote previously:
Today, we’ll take a closer look at the React part. It uses an internal library called proxy-compare for state usage tracking.
What is State Usage Tracking?
State usage tracking is the process of detecting which parts of the state are accessed. Let’s look at a simple example:
const state = { a: 1, b: 2 };
console.log(state.a);
// Now, `.a` is used, but `.b` isn't.
In this case, the state
object has two properties, but only .a
is accessed. .b
is completely unused.
We won’t go into full detail in this post, but tracking which parts of the state are actually used is important for reactivity. If we know .b
is never used, we can skip triggering reactivity when .b
changes.
Tracking State Usage with Proxies
How can we track state usage? One way is to use Proxies. Here’s a simple example:
const used = new Set();
const createProxy = (obj) => new Proxy(obj, {
get(target, prop) {
used.add(prop);
return target[prop];
},
});
With this, the earlier example works like this:
const state = createProxy({ a: 1, b: 2 });
console.log(state.a);
console.log([...used]); // ---> ['a']
We successfully track the usage of .a
, and we know .b
is unused. I hope you get the idea.
Alternative: Tracking with Object.defineProperty
The same kind of tracking can also be achieved with object properties instead of Proxies.
const used = new Set();
const createTrackingObject = (target) => {
const obj = {};
Object.keys(target).forEach((prop) => {
Object.defineProperty(obj, prop, {
get() {
used.add(prop);
return target[prop];
},
set(val) {
target[prop] = val;
},
});
});
return obj;
};
This works with the same example:
const state = createTrackingObject({ a: 1, b: 2 });
console.log(state.a);
console.log([...used]); // ---> ['a']
A Question for Readers
There is one big limitation with createTrackingObject
. I will leave it as a question for you to think about.
Happy coding.
Reply