@@ -390,6 +390,77 @@ preBuild.dependsOn("generateBrownfieldStore")
390390- [ ] Optimize re-renders on the JS side (selector support)
391391- [ ] Zustand integration
392392
393+ ## Re-render Optimization Plan
394+
395+ ### Problem
396+
397+ Both JS and Swift currently re-render all subscribers when any property changes.
398+
399+ **JS**: ` useBrownieStore ` returns full state → any change triggers all consumers
400+ **Swift**: ` @Published state ` replaced wholesale → all ` @UseStore ` views re-render
401+
402+ ### JavaScript Solution: Selector Hook
403+
404+ Add ` useBrownieStoreSelector ` that only re-renders when selected value changes:
405+
406+ ` ` ` ts
407+ function useBrownieStoreSelector <K extends keyof BrownieStores , T >(
408+ key : K ,
409+ selector : (state : BrownieStores [K ]) => T ,
410+ isEqual ? : (a : T , b : T ) => boolean
411+ ): T ;
412+ ` ` `
413+
414+ **Usage:**
415+
416+ ` ` ` ts
417+ const counter = useBrownieStoreSelector (' BrownfieldStore' , (s ) => s .counter );
418+ const user = useBrownieStoreSelector (' BrownfieldStore' , (s ) => s .user );
419+ ` ` `
420+
421+ **Implementation:**
422+
423+ 1. Store previous selected value in ` useRef `
424+ 2. On store change, run selector on new snapshot
425+ 3. Compare with previous using ` isEqual ` (default: ` Object .is ` )
426+ 4. Only trigger re-render if different
427+
428+ ### Swift Solution: Selector Property Wrapper
429+
430+ Add ` @UseStoreSelector ` that subscribes to specific keypath:
431+
432+ ` ` ` swift
433+ @propertyWrapper
434+ struct UseStoreSelector <State : BrownieStoreProtocol , Value : Equatable >: DynamicProperty {
435+ let keyPath: KeyPath <State , Value >
436+ @State private var value: Value
437+
438+ init(_ keyPath : KeyPath <State , Value >)
439+ var wrappedValue: Value { get }
440+ }
441+ ` ` `
442+
443+ **Usage:**
444+
445+ ` ` ` swift
446+ @UseStoreSelector (\.counter ) var counter : Int
447+ @UseStoreSelector (\.user ) var user : String
448+ ` ` `
449+
450+ **Implementation:**
451+
452+ 1. Use ` @State ` instead of ` @StateObject ` (no ` ObservableObject ` dependency)
453+ 2. Listen to ` BrownieStoreUpdated ` notification
454+ 3. Extract value via keyPath from C++ snapshot
455+ 4. Only update ` @State ` if value differs (Equatable check)
456+
457+ ### Tasks
458+
459+ - [ ] JS: Implement ` useBrownieStoreSelector ` hook
460+ - [ ] JS: Add ` isEqual ` option for custom comparison (objects/arrays)
461+ - [ ] Swift: Implement ` @UseStoreSelector ` property wrapper
462+ - [ ] Swift: Consider ` @Observable ` macro for iOS 17+ (automatic property tracking)
463+
393464### Distribution
394465
395466- [ ] Support xcframework packaging (iOS)
0 commit comments