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;
|
|
} |