Skip to content

Sync Behavior with Zustand

This document outlines how switching from useReducer/useState to Zustand would impact the event generation and synchronization flow.

1. Decoupling from the Render Cycle

STATUS: MITIGATED in current implementation. The Studio component currently uses the Ref Pattern to stabilize callbacks, ensuring React.memo works correctly for sibling nodes.

Current (Optimized useReducer):

  • The Studio component re-renders on state changes.
  • However, child components (MindMapNodeComponent) are passed stable callback references (via useRef/useCallback).
  • Sibling nodes DO NOT re-render on keystrokes because their props (node data and handler functions) remain reference-equal.
  • Performance is O(1) regarding the number of nodes (only the edited node renders).

With Zustand:

  • The store exists outside of React.
  • We can subscribe to state changes independently of React components.
  • Benefit: While performance is similar to the optimized useReducer approach (both avoid sibling renders), Zustand allows us to move logic entirely out of the React Component tree, resulting in cleaner files (Separation of Concerns).

2. Middleware for Side Effects

Current:

  • Data persistence logic is mixed into the Studio component or custom hooks (useAutoSave).

With Zustand:

  • We can implement a custom Sync Middleware.
  • This middleware can intercept actions (like UPDATE_TEXT) and handle the queueing logic directly.
  • Impact: Cleaner architecture. The UI components (Studio.tsx) generate events, but the "Wiring" to the database happens invisibly in the store layer.

3. Transient Updates

Current:

  • Typing updates the React state -> triggers Virtual DOM diffing -> updates DOM.
  • This is generally fast enough (~60fps) for text inputs unless the tree is massive.

With Zustand:

  • Enables Transient Updates (updating the store without triggering any React re-renders for listeners that haven't opted in).
  • Impact: For extremely high-frequency events (like 120hz mouse drag coordinates), using transient updates can bypass React entirely for smoother animation, though React's own performance is usually sufficient for text.

4. Does it fix the "Every Keystroke" Event?

Not automatically.

  • If we subscribe to the store and write to DB on every change, we still generate an event for every keystroke.
  • However, Zustand makes it easier to implement Debouncing or Throttling in the middleware or subscription layer:
    typescript
    // Easier to debounce in a store subscription than in a useEffect
    const save = debounce((nodes) => db.saveNodes(nodes), 500)
    useStore.subscribe((state) => save(state.nodes))

Summary Comparison

FeatureCurrent (Optimized useReducer)Zustand
Event GenerationCoupled to React Render CycleDecoupled (Store Subscription)
PerformanceGood: Sibling re-renders prevented via Ref PatternExcellent: Selective re-renders / Transient updates
Code StructureLogic mixed inside Component (Studio.tsx)Logic separated in Store / Middleware
Refactoring CostN/A (Already built)High (Rewrite state layer)

Conclusion: The move to Zustand would be primarily for Architectural Cleanliness (moving logic out of UI components) rather than a raw performance necessity, as the current implementation already solves the main re-render bottleneck.