Skip to content

🔄 Configurable Reaction Update Strategy for Performance Optimization #6

@flexsurfer

Description

@flexsurfer

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 draftDb in Reflex #5
  • All reactions, when marked dirty, recompute their value and use fast-deep-equal to 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.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions