You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							127 lines
						
					
					
						
							2.6 KiB
						
					
					
				
			
		
		
	
	
							127 lines
						
					
					
						
							2.6 KiB
						
					
					
				| import { getBatch } from './batch'; // encapsulates the subscription logic for connecting a component to the redux store, as
 | |
| // well as nesting subscriptions of descendant components, so that we can ensure the
 | |
| // ancestor components re-render before descendants
 | |
| 
 | |
| function createListenerCollection() {
 | |
|   const batch = getBatch();
 | |
|   let first = null;
 | |
|   let last = null;
 | |
|   return {
 | |
|     clear() {
 | |
|       first = null;
 | |
|       last = null;
 | |
|     },
 | |
| 
 | |
|     notify() {
 | |
|       batch(() => {
 | |
|         let listener = first;
 | |
| 
 | |
|         while (listener) {
 | |
|           listener.callback();
 | |
|           listener = listener.next;
 | |
|         }
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     get() {
 | |
|       let listeners = [];
 | |
|       let listener = first;
 | |
| 
 | |
|       while (listener) {
 | |
|         listeners.push(listener);
 | |
|         listener = listener.next;
 | |
|       }
 | |
| 
 | |
|       return listeners;
 | |
|     },
 | |
| 
 | |
|     subscribe(callback) {
 | |
|       let isSubscribed = true;
 | |
|       let listener = last = {
 | |
|         callback,
 | |
|         next: null,
 | |
|         prev: last
 | |
|       };
 | |
| 
 | |
|       if (listener.prev) {
 | |
|         listener.prev.next = listener;
 | |
|       } else {
 | |
|         first = listener;
 | |
|       }
 | |
| 
 | |
|       return function unsubscribe() {
 | |
|         if (!isSubscribed || first === null) return;
 | |
|         isSubscribed = false;
 | |
| 
 | |
|         if (listener.next) {
 | |
|           listener.next.prev = listener.prev;
 | |
|         } else {
 | |
|           last = listener.prev;
 | |
|         }
 | |
| 
 | |
|         if (listener.prev) {
 | |
|           listener.prev.next = listener.next;
 | |
|         } else {
 | |
|           first = listener.next;
 | |
|         }
 | |
|       };
 | |
|     }
 | |
| 
 | |
|   };
 | |
| }
 | |
| 
 | |
| const nullListeners = {
 | |
|   notify() {},
 | |
| 
 | |
|   get: () => []
 | |
| };
 | |
| export function createSubscription(store, parentSub) {
 | |
|   let unsubscribe;
 | |
|   let listeners = nullListeners;
 | |
| 
 | |
|   function addNestedSub(listener) {
 | |
|     trySubscribe();
 | |
|     return listeners.subscribe(listener);
 | |
|   }
 | |
| 
 | |
|   function notifyNestedSubs() {
 | |
|     listeners.notify();
 | |
|   }
 | |
| 
 | |
|   function handleChangeWrapper() {
 | |
|     if (subscription.onStateChange) {
 | |
|       subscription.onStateChange();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function isSubscribed() {
 | |
|     return Boolean(unsubscribe);
 | |
|   }
 | |
| 
 | |
|   function trySubscribe() {
 | |
|     if (!unsubscribe) {
 | |
|       unsubscribe = parentSub ? parentSub.addNestedSub(handleChangeWrapper) : store.subscribe(handleChangeWrapper);
 | |
|       listeners = createListenerCollection();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function tryUnsubscribe() {
 | |
|     if (unsubscribe) {
 | |
|       unsubscribe();
 | |
|       unsubscribe = undefined;
 | |
|       listeners.clear();
 | |
|       listeners = nullListeners;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   const subscription = {
 | |
|     addNestedSub,
 | |
|     notifyNestedSubs,
 | |
|     handleChangeWrapper,
 | |
|     isSubscribed,
 | |
|     trySubscribe,
 | |
|     tryUnsubscribe,
 | |
|     getListeners: () => listeners
 | |
|   };
 | |
|   return subscription;
 | |
| } |