-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
Summary
Reflex currently uses a universal fast-deep-equal check inside every reaction to determine whether to update and notify downstream dependents. While this ensures correctness, it may cause performance issues depending on the app's data structure and computational characteristics.
This issue proposes making the reaction update strategy configurable to better support different performance profiles.
Current Behavior
- Root reactions are marked dirty whenever a patch affects their associated key. ✅ Best Practices for Mutating
draftDbin Reflex #5 - All reactions, when marked dirty, recompute their value and use
fast-deep-equalto check for changes. - If the value changes, downstream reactions are triggered.
This means:
- Deep comparisons happen on every dirty reaction, regardless of how trivial the actual change was.
Problems
| Scenario | Optimal Strategy | Why |
|---|---|---|
| Small data, expensive compute | deep |
Avoid recomputing |
| Large data, cheap compute | none |
Avoid expensive deepEqual |
| Predictable / manual mutation | none + manual dirty |
Full control |
| Complex nested updates | custom hasChanged() |
Precision |
Proposal
Introduce configurable reaction update strategies, both per reaction and globally:
createReaction(fn, deps, {
equality: 'deep' | 'shallow' | 'none', // default: 'deep'
hasChanged?: (prev: T, next: T) => boolean // optional custom comparator
})Strategy options:
| Strategy | Description | Use case |
|---|---|---|
'deep' |
Uses fast-deep-equal |
Safe default |
'shallow' |
Uses shallow comparison (Object.is, per-field) |
Flat or primitive state |
'none' |
Always recomputes | Cheap compute, fast paths |
hasChanged() |
Developer-defined comparator | Full flexibility |
Why This Matters
Reflex's current design favors correctness by always checking values via deepEqual. But this introduces runtime cost in many scenarios.
Adding configurable reaction update strategies gives developers:
- Control over performance vs correctness tradeoffs
- Optimizations for edge cases (large trees, frequent mutations)
- Simpler tuning for real-world apps with varied usage patterns
Next Steps
- Discuss feasibility of per-reaction strategy config
- Optionally add global config fallback
✳️ Open for discussion and feedback.
Reactions are currently unavailable