I like how you properly used useSyncExternalStore and AbortController for signaling. Always a good sign seeing good use of APIs.
(EDIT) Quick question: will computed values be lazy and cached? I'm worried changing an atom could trigger a huge cascade of changes (most of which will not even be observed) but also that expensive values could get thrown away once not observed anymore (even if briefly, think e.g. a quick remount) but also that it might get cached for too long (or never discarded).
How is all this handled internally?
(EDIT2) I'm reading through the README and the rationale/comparison with Jotai looks very solid. I'm really impressed. Kudos.
Thank you for your question. This is a crucial part of CCState, and I plan to include this answer directly in the documentation.
In short, a Computed atom is lazy if it's not directly or indirectly subscribed to. Otherwise, it will recalculate immediately when any of its dependencies change.
For example, consider A(Computed) -> B(Computed) -> C(State):
- If no atoms are subscribed to, updates to C will have a lazy effect on both A and B
- If A is subscribed to, C's updates will synchronously trigger recalculations of both B and A, then notify A's subscribers
- If B is subscribed, C's updates will synchronously trigger B's recalculation and notify B's subscribers, while A remains unaffected
This is the current behavior almost identical to Jotai's implementation.
However, while writing this answer, I realized this could potentially be simpler. Jotai's design choice stems from its notification mechanism, which performs distinct events. This means Jotai must re-evaluate immediately after a set operation to determine whether to notify its subscribers. This is one of Jotai's "magic" features, but in CCState, I try to avoid such magic. CCState doesn't perform event deduplication during notifications (though we might consider providing some higher-order functions later, but this won't be part of the core design). Therefore, perhaps CCState could make Computed evaluations always lazy.
[EDIT]: As long as subscriber notifications are synchronous, Computed atoms must be recalculated synchronously. Otherwise, dependency analysis will have issues. I've written two test cases, https://codesandbox.io/p/sandbox/t2vl2m
Mobx has similar patterns with the computeds. They allow you to have a little more control over their lifecycle. The general rule is that they’re kept alive until they’re no longer observed but you can pass a flag to keep them around even when they’re not needed.
Interesting! Will give it a try.
I like how you properly used useSyncExternalStore and AbortController for signaling. Always a good sign seeing good use of APIs.
(EDIT) Quick question: will computed values be lazy and cached? I'm worried changing an atom could trigger a huge cascade of changes (most of which will not even be observed) but also that expensive values could get thrown away once not observed anymore (even if briefly, think e.g. a quick remount) but also that it might get cached for too long (or never discarded).
How is all this handled internally?
(EDIT2) I'm reading through the README and the rationale/comparison with Jotai looks very solid. I'm really impressed. Kudos.
Thank you for your question. This is a crucial part of CCState, and I plan to include this answer directly in the documentation.
In short, a Computed atom is lazy if it's not directly or indirectly subscribed to. Otherwise, it will recalculate immediately when any of its dependencies change.
For example, consider A(Computed) -> B(Computed) -> C(State):
- If no atoms are subscribed to, updates to C will have a lazy effect on both A and B
- If A is subscribed to, C's updates will synchronously trigger recalculations of both B and A, then notify A's subscribers
- If B is subscribed, C's updates will synchronously trigger B's recalculation and notify B's subscribers, while A remains unaffected
This is the current behavior almost identical to Jotai's implementation.
However, while writing this answer, I realized this could potentially be simpler. Jotai's design choice stems from its notification mechanism, which performs distinct events. This means Jotai must re-evaluate immediately after a set operation to determine whether to notify its subscribers. This is one of Jotai's "magic" features, but in CCState, I try to avoid such magic. CCState doesn't perform event deduplication during notifications (though we might consider providing some higher-order functions later, but this won't be part of the core design). Therefore, perhaps CCState could make Computed evaluations always lazy.
[EDIT]: As long as subscriber notifications are synchronous, Computed atoms must be recalculated synchronously. Otherwise, dependency analysis will have issues. I've written two test cases, https://codesandbox.io/p/sandbox/t2vl2m
[EDIT 2]: I've added the relevant behaviors to the documentation. I hope I've explained it clearly. https://github.com/e7h4n/ccstate?tab=readme-ov-file#when-com...
Mobx has similar patterns with the computeds. They allow you to have a little more control over their lifecycle. The general rule is that they’re kept alive until they’re no longer observed but you can pass a flag to keep them around even when they’re not needed.