createStore: Fine-Grained Deep Proxy Path Mutation Tracking
- Last updated
- Prerequisites:
- JavaScript Proxy traps
- SolidJS createSignal
- solidjs
- createStore
- store
- proxy
- reconciliation
- nested-reactivity
Read at your depth
The practical view
`createStore` creates deeply reactive tree structures (objects and arrays). `const [state, setState] = createStore({ user: { profile: { name: 'Ada' } }, todos: [] });`. Unlike `createSignal` (where updating a nested field requires cloning the entire parent object), `createStore` uses path-based setters: `setState('user', 'profile', 'name', 'Grace')`. Only components reading that exact nested property update.
The same idea in other frameworks
Immer `produce` or Zustand creating immutable object clones on every mutation.Deeply nested Signals or RxJS `patchState` operators in NgRx SignalStore.Vue 3 `reactive()` deep proxy wrapping.Svelte 5 `$state({ user: { name: 'Ada' } })` deep proxy mutations.Legacy vs modern
Signal Object Cloning vs Solid Store Surgical Path Update
Updating nested objects in signals requires immutable cloning of all parent levels; `createStore` modifies leaf properties directly.
setUser(u => ({ ...u, profile: { ...u.profile, name: 'Grace' } })); // ❌ Full tree cloningsetState('profile', 'name', 'Grace'); // ✅ NEW: Zero cloning, updates only 'name' subscribersInterview gotchas
Context
Interviewers test your knowledge of backend API integration with fine-grained stores.
The mechanical answer
When replacing a store array or object with a fresh API response (`setUser(reconcile(freshData))`), `reconcile()` diffs the new data against the existing store objects by key/ID. It applies updates only to fields that changed, preserves unchanged object references, and avoids triggering unneeded subscriber notifications, preventing UI flicker.
Trap
Using `setState(freshData)` directly without `reconcile()` replaces all object references, forcing all components reading any property of the store to re-evaluate.
Context
Checks understanding of proxy unwrapping for external library interop.
The mechanical answer
`unwrap(state)` strips the reactive Proxy wrappers and returns the underlying raw JavaScript object tree. This is necessary when passing data to third-party non-reactive libraries (like charting libraries, Web Workers via `postMessage`, or `structuredClone`), which can fail or degrade in performance if given Proxy instances.
Trap
Do not mutate the object returned by `unwrap()`; raw mutations bypass the reactivity graph and will not notify UI subscribers.