source: node_modules/react-redux/src/utils/Subscription.ts

Last change on this file was a762898, checked in by istevanoska <ilinastevanoska@…>, 5 months ago

Added visualizations

  • Property mode set to 100644
File size: 3.9 KB
Line 
1import { defaultNoopBatch as batch } from './batch'
2
3// encapsulates the subscription logic for connecting a component to the redux store, as
4// well as nesting subscriptions of descendant components, so that we can ensure the
5// ancestor components re-render before descendants
6
7type VoidFunc = () => void
8
9type Listener = {
10 callback: VoidFunc
11 next: Listener | null
12 prev: Listener | null
13}
14
15function createListenerCollection() {
16 let first: Listener | null = null
17 let last: Listener | null = null
18
19 return {
20 clear() {
21 first = null
22 last = null
23 },
24
25 notify() {
26 batch(() => {
27 let listener = first
28 while (listener) {
29 listener.callback()
30 listener = listener.next
31 }
32 })
33 },
34
35 get() {
36 const listeners: Listener[] = []
37 let listener = first
38 while (listener) {
39 listeners.push(listener)
40 listener = listener.next
41 }
42 return listeners
43 },
44
45 subscribe(callback: () => void) {
46 let isSubscribed = true
47
48 const listener: Listener = (last = {
49 callback,
50 next: null,
51 prev: last,
52 })
53
54 if (listener.prev) {
55 listener.prev.next = listener
56 } else {
57 first = listener
58 }
59
60 return function unsubscribe() {
61 if (!isSubscribed || first === null) return
62 isSubscribed = false
63
64 if (listener.next) {
65 listener.next.prev = listener.prev
66 } else {
67 last = listener.prev
68 }
69 if (listener.prev) {
70 listener.prev.next = listener.next
71 } else {
72 first = listener.next
73 }
74 }
75 },
76 }
77}
78
79type ListenerCollection = ReturnType<typeof createListenerCollection>
80
81export interface Subscription {
82 addNestedSub: (listener: VoidFunc) => VoidFunc
83 notifyNestedSubs: VoidFunc
84 handleChangeWrapper: VoidFunc
85 isSubscribed: () => boolean
86 onStateChange?: VoidFunc | null
87 trySubscribe: VoidFunc
88 tryUnsubscribe: VoidFunc
89 getListeners: () => ListenerCollection
90}
91
92const nullListeners = {
93 notify() {},
94 get: () => [],
95} as unknown as ListenerCollection
96
97export function createSubscription(store: any, parentSub?: Subscription) {
98 let unsubscribe: VoidFunc | undefined
99 let listeners: ListenerCollection = nullListeners
100
101 // Reasons to keep the subscription active
102 let subscriptionsAmount = 0
103
104 // Is this specific subscription subscribed (or only nested ones?)
105 let selfSubscribed = false
106
107 function addNestedSub(listener: () => void) {
108 trySubscribe()
109
110 const cleanupListener = listeners.subscribe(listener)
111
112 // cleanup nested sub
113 let removed = false
114 return () => {
115 if (!removed) {
116 removed = true
117 cleanupListener()
118 tryUnsubscribe()
119 }
120 }
121 }
122
123 function notifyNestedSubs() {
124 listeners.notify()
125 }
126
127 function handleChangeWrapper() {
128 if (subscription.onStateChange) {
129 subscription.onStateChange()
130 }
131 }
132
133 function isSubscribed() {
134 return selfSubscribed
135 }
136
137 function trySubscribe() {
138 subscriptionsAmount++
139 if (!unsubscribe) {
140 unsubscribe = parentSub
141 ? parentSub.addNestedSub(handleChangeWrapper)
142 : store.subscribe(handleChangeWrapper)
143
144 listeners = createListenerCollection()
145 }
146 }
147
148 function tryUnsubscribe() {
149 subscriptionsAmount--
150 if (unsubscribe && subscriptionsAmount === 0) {
151 unsubscribe()
152 unsubscribe = undefined
153 listeners.clear()
154 listeners = nullListeners
155 }
156 }
157
158 function trySubscribeSelf() {
159 if (!selfSubscribed) {
160 selfSubscribed = true
161 trySubscribe()
162 }
163 }
164
165 function tryUnsubscribeSelf() {
166 if (selfSubscribed) {
167 selfSubscribed = false
168 tryUnsubscribe()
169 }
170 }
171
172 const subscription: Subscription = {
173 addNestedSub,
174 notifyNestedSubs,
175 handleChangeWrapper,
176 isSubscribed,
177 trySubscribe: trySubscribeSelf,
178 tryUnsubscribe: tryUnsubscribeSelf,
179 getListeners: () => listeners,
180 }
181
182 return subscription
183}
Note: See TracBrowser for help on using the repository browser.