浏览代码

StateListenerRegistry

"Middleware" redux state changes, not actions.
master
Lyubo Marinov 7 年前
父节点
当前提交
db21e97c19

+ 8
- 1
react/features/app/components/AbstractApp.js 查看文件

@@ -10,7 +10,11 @@ import Thunk from 'redux-thunk';
10 10
 import { i18next } from '../../base/i18n';
11 11
 import { localParticipantLeft } from '../../base/participants';
12 12
 import { Fragment, RouteRegistry } from '../../base/react';
13
-import { MiddlewareRegistry, ReducerRegistry } from '../../base/redux';
13
+import {
14
+    MiddlewareRegistry,
15
+    ReducerRegistry,
16
+    StateListenerRegistry
17
+} from '../../base/redux';
14 18
 import { SoundCollection } from '../../base/sounds';
15 19
 import { PersistenceRegistry } from '../../base/storage';
16 20
 import { toURLString } from '../../base/util';
@@ -404,6 +408,9 @@ export class AbstractApp extends Component {
404 408
             }
405 409
         }
406 410
 
411
+        // StateListenerRegistry
412
+        store && StateListenerRegistry.subscribe(store);
413
+
407 414
         return store;
408 415
     }
409 416
 

+ 159
- 0
react/features/base/redux/StateListenerRegistry.js 查看文件

@@ -0,0 +1,159 @@
1
+// @flow
2
+
3
+const logger = require('jitsi-meet-logger').getLogger(__filename);
4
+
5
+/**
6
+ * The type listener supported for registration with
7
+ * {@link StateListenerRegistry} in association with a {@link Selector}.
8
+ *
9
+ * @param {any} selection - The value derived from the redux store/state by the
10
+ * associated {@code Selector}. Immutable!
11
+ * @param {Store} store - The redux store. Provided in case the {@code Listener}
12
+ * needs to {@code dispatch} or {@code getState}. The latter is advisable only
13
+ * if the {@code Listener} is not to respond to changes to that state.
14
+ * @param {any} prevSelection - The value previously derived from the redux
15
+ * store/state by the associated {@code Selector}. The {@code Listener} is
16
+ * invoked only if {@code prevSelection} and {@code selection} are different.
17
+ * Immutable!
18
+ */
19
+type Listener = (selection: any, store: Store, prevSelection: any) => void;
20
+
21
+/**
22
+ * The type selector supported for registration with
23
+ * {@link StateListenerRegistry} in association with a {@link Listener}.
24
+ *
25
+ * @param {Object} state - The redux state from which the {@code Selector} is to
26
+ * derive data.
27
+ * @param {any} prevSelection - The value previously derived from the redux
28
+ * store/state by the {@code Selector}. Provided in case the {@code Selector}
29
+ * needs to derive the returned value from the specified {@code state} and
30
+ * {@code prevSelection}. Immutable!
31
+ * @returns {any} The value derived from the specified {@code state} and/or
32
+ * {@code prevSelection}. The associated {@code Listener} will only be invoked
33
+ * if the returned value is other than {@code prevSelection}.
34
+ */
35
+type Selector = (state: Object, prevSelection: any) => any;
36
+
37
+/**
38
+ * A type of a {@link Selector}-{@link Listener} association in which the
39
+ * {@code Listener} listens to changes in the values derived from a redux
40
+ * store/state by the {@code Selector}.
41
+ */
42
+type SelectorListener = {
43
+
44
+    /**
45
+     * The {@code Listener} which listens to changes in the values selected by
46
+     * {@link selector}.
47
+     */
48
+    listener: Listener,
49
+
50
+    /**
51
+     * The {@code Selector} which selects values whose changes are listened to
52
+     * by {@link listener}.
53
+     */
54
+    selector: Selector
55
+};
56
+
57
+/**
58
+ * A registry listeners which listen to changes in a redux store/state.
59
+ */
60
+class StateListenerRegistry {
61
+    /**
62
+     * The {@link Listener}s registered with this {@code StateListenerRegistry}
63
+     * to be notified when the values derived by associated {@link Selector}s
64
+     * from a redux store/state change.
65
+     */
66
+    _selectorListeners: Set<SelectorListener> = new Set();
67
+
68
+    _listener: (Store) => void;
69
+
70
+    /**
71
+     * Invoked by a specific redux store any time an action is dispatched, and
72
+     * some part of the state (tree) may potentially have changed.
73
+     *
74
+     * @param {Object} context - The redux store invoking the listener and the
75
+     * private state of this {@code StateListenerRegistry} associated with the
76
+     * redux store.
77
+     * @returns {void}
78
+     */
79
+    _listener({ prevSelections, store }: {
80
+            prevSelections: Map<SelectorListener, any>,
81
+            store: Store
82
+    }) {
83
+        for (const selectorListener of this._selectorListeners) {
84
+            const prevSelection = prevSelections.get(selectorListener);
85
+
86
+            try {
87
+                const selection
88
+                    = selectorListener.selector(
89
+                        store.getState(),
90
+                        prevSelection);
91
+
92
+                if (prevSelection !== selection) {
93
+                    prevSelections.set(selectorListener, selection);
94
+                    selectorListener.listener(selection, store, prevSelection);
95
+                }
96
+            } catch (e) {
97
+                // Don't let one faulty listener prevent other listeners from
98
+                // being notified about their associated changes.
99
+                logger.error(e);
100
+            }
101
+        }
102
+    }
103
+
104
+    /**
105
+     * Registers a specific listener to be notified when the value derived by a
106
+     * specific {@code selector} from a redux store/state changes.
107
+     *
108
+     * @param {Function} selector - The pure {@code Function} of the redux
109
+     * store/state (and the previous selection of made by {@code selector})
110
+     * which selects the value listened to by the specified {@code listener}.
111
+     * @param {Function} listener - The listener to register with this
112
+     * {@code StateListenerRegistry} so that it gets invoked when the value
113
+     * returned by the specified {@code selector} changes.
114
+     * @returns {void}
115
+     */
116
+    register(selector: Selector, listener: Listener) {
117
+        this._selectorListeners.add({
118
+            listener,
119
+            selector
120
+        });
121
+    }
122
+
123
+    /**
124
+     * Subscribes to a specific redux store (so that this instance gets notified
125
+     * any time an action is dispatched, and some part of the state (tree) of
126
+     * the specified redux store may potentially have changed).
127
+     *
128
+     * @param {Store} store - The redux store to which this
129
+     * {@code StateListenerRegistry} is to {@code subscribe}.
130
+     * @returns {void}
131
+     */
132
+    subscribe(store: Store) {
133
+        // XXX If StateListenerRegistry is not utilized by the app to listen to
134
+        // state changes, do not bother subscribing to the store at all.
135
+        if (this._selectorListeners.size) {
136
+            store.subscribe(
137
+                this._listener.bind(
138
+                    this,
139
+                    {
140
+                        /**
141
+                         * The previous selections of the {@code Selector}s
142
+                         * registered with this {@code StateListenerRegistry}.
143
+                         *
144
+                         * @type Map<any>
145
+                         */
146
+                        prevSelections: new Map(),
147
+
148
+                        /**
149
+                         * The redux store.
150
+                         *
151
+                         * @type Store
152
+                         */
153
+                        store
154
+                    }));
155
+        }
156
+    }
157
+}
158
+
159
+export default new StateListenerRegistry();

+ 1
- 0
react/features/base/redux/index.js 查看文件

@@ -1,3 +1,4 @@
1 1
 export * from './functions';
2 2
 export { default as MiddlewareRegistry } from './MiddlewareRegistry';
3 3
 export { default as ReducerRegistry } from './ReducerRegistry';
4
+export { default as StateListenerRegistry } from './StateListenerRegistry';

正在加载...
取消
保存