|
1 | | -import { removeFromList, assign } from './util' |
| 1 | +import { removeFromList } from './util' |
2 | 2 | import $$observable from 'symbol-observable' |
3 | 3 | import ReduxComponent from './ReduxComponent' |
4 | 4 |
|
@@ -34,34 +34,56 @@ subjectMixin = { |
34 | 34 | } |
35 | 35 | } |
36 | 36 |
|
| 37 | +# Property definition for Symbol.observable |
| 38 | +observablePropertyDefinition = { writable: true, configurable: true, value: (-> @) } |
| 39 | + |
| 40 | +selectorIsBeingObserved = (isBeingObserved) -> |
| 41 | + selector = @; componentInstance = @__componentInstance |
| 42 | + if isBeingObserved |
| 43 | + lastSeenValue = undefined |
| 44 | + |
| 45 | + # If component isn't mounted, defer. |
| 46 | + if not componentInstance.isMounted() |
| 47 | + componentInstance.__deferObservedSelectors = (componentInstance.__deferObservedSelectors or []).concat([selector]) |
| 48 | + return |
| 49 | + |
| 50 | + # Closure to detect changes in the selector. |
| 51 | + observeState = -> |
| 52 | + val = selector(componentInstance.store.getState()) |
| 53 | + if val isnt lastSeenValue |
| 54 | + lastSeenValue = val; selector.next(val) |
| 55 | + |
| 56 | + # Connect to the store; observe the initial state. |
| 57 | + @__unsubscriber = componentInstance.store.subscribe(observeState) |
| 58 | + observeState() |
| 59 | + else |
| 60 | + # If component isn't mounted, clear deferral. |
| 61 | + if not componentInstance.isMounted() |
| 62 | + removeFromList(componentInstance.__deferObservedSelectors, selector) |
| 63 | + return |
| 64 | + |
| 65 | + # Unsubscribe from the store if previously subscribed. |
| 66 | + @__unsubscriber?(); delete @__unsubscriber |
| 67 | + undefined |
| 68 | + |
37 | 69 | # Make a selector on a ReduxComponentInstance into an ES7 Observable. |
38 | 70 | export default makeSelectorObservable = (componentInstance, selector) -> |
39 | 71 | # Make the selector a Subject. |
40 | | - assign(selector, subjectMixin) |
41 | | - |
| 72 | + Object.assign(selector, subjectMixin) |
42 | 73 | # Make the selector an ES7 Observable |
43 | | - Object.defineProperty(selector, $$observable, { writable: true, configurable: true, value: (-> @) }) |
44 | | - |
45 | | - # Attach the selector to the Redux store when it is being observed. |
46 | | - selector.__isBeingObserved = (isBeingObserved) -> |
47 | | - if isBeingObserved |
48 | | - lastSeenValue = undefined |
49 | | - observeState = -> |
50 | | - val = selector(componentInstance.store.getState()) |
51 | | - if val isnt lastSeenValue |
52 | | - lastSeenValue = val; selector.next(val) |
53 | | - |
54 | | - @__unsubscriber = componentInstance.store.subscribe(observeState) |
55 | | - observeState() |
56 | | - else |
57 | | - @__unsubscriber?(); delete @__unsubscriber |
58 | | - undefined |
| 74 | + Object.defineProperty(selector, $$observable, observablePropertyDefinition) |
| 75 | + # Store the componentInstance on the selector. |
| 76 | + selector.__componentInstance = componentInstance |
| 77 | + # Attach the observation function |
| 78 | + selector.__isBeingObserved = selectorIsBeingObserved |
| 79 | + # Return the selector |
| 80 | + selector |
59 | 81 |
|
60 | 82 | # Make all selectors on the given component instance observable. |
61 | 83 | export makeSelectorsObservable = (componentInstance) -> |
62 | 84 | if not (componentInstance instanceof ReduxComponent) |
63 | 85 | throw new Error("makeSelectorsObservable: argument must be instanceof ReduxComponent") |
64 | | - |
| 86 | + |
65 | 87 | if componentInstance.selectors |
66 | 88 | makeSelectorObservable(componentInstance, componentInstance[selKey]) for selKey of componentInstance.selectors |
67 | 89 | componentInstance |
0 commit comments