"Fossies" - the Fresh Open Source Software Archive 
Member "jitsi-meet-7555/react/features/base/redux/StateListenerRegistry.ts" (28 Sep 2023, 7018 Bytes) of package /linux/misc/jitsi-meet-7555.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TypeScript source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 import { Store } from 'redux';
2
3 import { IReduxState, IStore } from '../../app/types';
4
5 import { equals } from './functions';
6 import logger from './logger';
7
8 /**
9 * The type listener supported for registration with
10 * {@link StateListenerRegistry} in association with a {@link Selector}.
11 *
12 * @param {any} selection - The value derived from the redux store/state by the
13 * associated {@code Selector}. Immutable!
14 * @param {Store} store - The redux store. Provided in case the {@code Listener}
15 * needs to {@code dispatch} or {@code getState}. The latter is advisable only
16 * if the {@code Listener} is not to respond to changes to that state.
17 * @param {any} prevSelection - The value previously derived from the redux
18 * store/state by the associated {@code Selector}. The {@code Listener} is
19 * invoked only if {@code prevSelection} and {@code selection} are different.
20 * Immutable!
21 */
22 type Listener
23 = (selection: any, store: IStore, prevSelection: any) => void;
24
25 /**
26 * The type selector supported for registration with
27 * {@link StateListenerRegistry} in association with a {@link Listener}.
28 *
29 * @param {IReduxState} state - The redux state from which the {@code Selector} is to
30 * derive data.
31 * @param {any} prevSelection - The value previously derived from the redux
32 * store/state by the {@code Selector}. Provided in case the {@code Selector}
33 * needs to derive the returned value from the specified {@code state} and
34 * {@code prevSelection}. Immutable!
35 * @returns {any} The value derived from the specified {@code state} and/or
36 * {@code prevSelection}. The associated {@code Listener} will only be invoked
37 * if the returned value is other than {@code prevSelection}.
38 */
39 type Selector = (state: IReduxState, prevSelection: any) => any;
40
41 /**
42 * Options that can be passed to the register method.
43 */
44 type RegistrationOptions = {
45
46 /**
47 * @property {boolean} [deepEquals=false] - Whether or not a deep equals check should be performed on the selection
48 * returned by {@link Selector}.
49 */
50 deepEquals?: boolean;
51 };
52
53 /**
54 * A type of a {@link Selector}-{@link Listener} association in which the
55 * {@code Listener} listens to changes in the values derived from a redux
56 * store/state by the {@code Selector}.
57 */
58 type SelectorListener = {
59
60 /**
61 * The {@code Listener} which listens to changes in the values selected by
62 * {@link selector}.
63 */
64 listener: Listener;
65
66 /**
67 * The {@link RegistrationOptions} passed during the registration to be applied on the listener.
68 */
69 options?: RegistrationOptions;
70
71 /**
72 * The {@code Selector} which selects values whose changes are listened to
73 * by {@link listener}.
74 */
75 selector: Selector;
76 };
77
78 /**
79 * A registry listeners which listen to changes in a redux store/state.
80 */
81 class StateListenerRegistry {
82 /**
83 * The {@link Listener}s registered with this {@code StateListenerRegistry}
84 * to be notified when the values derived by associated {@link Selector}s
85 * from a redux store/state change.
86 */
87 _selectorListeners: Set<SelectorListener> = new Set();
88
89 /**
90 * Invoked by a specific redux store any time an action is dispatched, and
91 * some part of the state (tree) may potentially have changed.
92 *
93 * @param {Object} context - The redux store invoking the listener and the
94 * private state of this {@code StateListenerRegistry} associated with the
95 * redux store.
96 * @returns {void}
97 */
98 _listener({ prevSelections, store }: {
99 prevSelections: Map<SelectorListener, any>;
100 store: Store<any, any>;
101 }) {
102 for (const selectorListener of this._selectorListeners) {
103 const prevSelection = prevSelections.get(selectorListener);
104
105 try {
106 const selection
107 = selectorListener.selector(
108 store.getState(),
109 prevSelection);
110 const useDeepEquals = selectorListener?.options?.deepEquals;
111
112 if ((useDeepEquals && !equals(prevSelection, selection))
113 || (!useDeepEquals && prevSelection !== selection)) {
114 prevSelections.set(selectorListener, selection);
115 selectorListener.listener(selection, store, prevSelection);
116 }
117 } catch (e) {
118 // Don't let one faulty listener prevent other listeners from
119 // being notified about their associated changes.
120 logger.error(e);
121 }
122 }
123 }
124
125 /**
126 * Registers a specific listener to be notified when the value derived by a
127 * specific {@code selector} from a redux store/state changes.
128 *
129 * @param {Function} selector - The pure {@code Function} of the redux
130 * store/state (and the previous selection of made by {@code selector})
131 * which selects the value listened to by the specified {@code listener}.
132 * @param {Function} listener - The listener to register with this
133 * {@code StateListenerRegistry} so that it gets invoked when the value
134 * returned by the specified {@code selector} changes.
135 * @param {RegistrationOptions} [options] - Any options to be applied to the registration.
136 * @returns {void}
137 */
138 register(selector: Selector, listener: Listener, options?: RegistrationOptions) {
139 if (typeof selector !== 'function' || typeof listener !== 'function') {
140 throw new Error('Invalid selector or listener!');
141 }
142
143 this._selectorListeners.add({
144 listener,
145 selector,
146 options
147 });
148 }
149
150 /**
151 * Subscribes to a specific redux store (so that this instance gets notified
152 * any time an action is dispatched, and some part of the state (tree) of
153 * the specified redux store may potentially have changed).
154 *
155 * @param {Store} store - The redux store to which this
156 * {@code StateListenerRegistry} is to {@code subscribe}.
157 * @returns {void}
158 */
159 subscribe(store: Store<any, any>) {
160 // XXX If StateListenerRegistry is not utilized by the app to listen to
161 // state changes, do not bother subscribing to the store at all.
162 if (this._selectorListeners.size) {
163 store.subscribe(
164 this._listener.bind(
165 this,
166 {
167 /**
168 * The previous selections of the {@code Selector}s
169 * registered with this {@code StateListenerRegistry}.
170 *
171 * @type Map<any>
172 */
173 prevSelections: new Map(),
174
175 /**
176 * The redux store.
177 *
178 * @type Store
179 */
180 store
181 }));
182 }
183 }
184 }
185
186 export default new StateListenerRegistry();