diff --git a/routes/_components/pseudoVirtualList/PseudoVirtualList.html b/routes/_components/pseudoVirtualList/PseudoVirtualList.html index 9e9f6694..d07ae0e4 100644 --- a/routes/_components/pseudoVirtualList/PseudoVirtualList.html +++ b/routes/_components/pseudoVirtualList/PseudoVirtualList.html @@ -29,7 +29,7 @@ export default { oncreate() { mark('PseudoVirtualList oncreate()') - this.store.set({currentRealm: this.get('realm')}) + this.store.setCurrentRealm(this.get('realm')) // When re-rendering, assume all items are non-intersecting until told otherwise. // We already have the heights cached. diff --git a/routes/_components/pseudoVirtualList/pseudoVirtualListStore.js b/routes/_components/pseudoVirtualList/pseudoVirtualListStore.js index f0faada6..5988a405 100644 --- a/routes/_components/pseudoVirtualList/pseudoVirtualListStore.js +++ b/routes/_components/pseudoVirtualList/pseudoVirtualListStore.js @@ -1,21 +1,14 @@ -import { Store } from 'svelte/store.js' +import { RealmStore } from '../../_utils/RealmStore' -class PseudoVirtualListStore extends Store { - setForRealm(obj) { - let realmName = this.get('currentRealm') - let realms = this.get('realms') || {} - realms[realmName] = Object.assign(realms[realmName] || {}, obj) - this.set({realms: realms}) +class PseudoVirtualListStore extends RealmStore { + constructor(state) { + super(state, /* maxSize */ 10) } } const pseudoVirtualListStore = new PseudoVirtualListStore() -pseudoVirtualListStore.compute('intersectionStates', - ['realms', 'currentRealm'], - (realms, currentRealm) => { - return (realms && realms[currentRealm] && realms[currentRealm].intersectionStates) || {} -}) +pseudoVirtualListStore.computeForRealm('intersectionStates', {}) if (process.browser && process.env.NODE_NODE !== 'production') { window.pseudoVirtualListStore = pseudoVirtualListStore diff --git a/routes/_components/virtualList/VirtualListContainer.html b/routes/_components/virtualList/VirtualListContainer.html index d67fc24b..f2a679f6 100644 --- a/routes/_components/virtualList/VirtualListContainer.html +++ b/routes/_components/virtualList/VirtualListContainer.html @@ -17,8 +17,7 @@ oncreate() { mark('onCreate VirtualListContainer') let node = this.refs.node - let realm = this.get('realm') - this.store.set({currentRealm: realm}) + this.store.setCurrentRealm(this.get('realm')) let scrollTop = this.store.get('scrollTop') if (scrollTop > 0) { this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => { diff --git a/routes/_components/virtualList/virtualListStore.js b/routes/_components/virtualList/virtualListStore.js index 834f4471..51cd09ed 100644 --- a/routes/_components/virtualList/virtualListStore.js +++ b/routes/_components/virtualList/virtualListStore.js @@ -1,11 +1,11 @@ -import { Store } from 'svelte/store.js' import { mark, stop } from '../../_utils/marks' +import { RealmStore } from '../../_utils/RealmStore' const VIEWPORT_RENDER_FACTOR = 4 -class VirtualListStore extends Store { +class VirtualListStore extends RealmStore { constructor(state) { - super(state) + super(state, /* maxSize */ 10) this._batches = {} } @@ -37,41 +37,18 @@ class VirtualListStore extends Store { stop('batchUpdate()') }) } - - setForRealm(obj) { - let realmName = this.get('currentRealm') - let realms = this.get('realms') || {} - realms[realmName] = Object.assign(realms[realmName] || {}, obj) - this.set({realms: realms}) - } } const virtualListStore = new VirtualListStore({ - realms: {}, - currentRealm: null, itemHeights: {}, footerHeight: 0 }) -virtualListStore.compute('items', ['currentRealm', 'realms'], (currentRealm, realms) => { - return realms[currentRealm] && realms[currentRealm].items || [] -}) - -virtualListStore.compute('showFooter', ['currentRealm', 'realms'], (currentRealm, realms) => { - return realms[currentRealm] && realms[currentRealm].showFooter -}) - -virtualListStore.compute('scrollTop', ['currentRealm', 'realms'], (currentRealm, realms) => { - return realms[currentRealm] && realms[currentRealm].scrollTop || 0 -}) - -virtualListStore.compute('scrollHeight', ['currentRealm', 'realms'], (currentRealm, realms) => { - return realms[currentRealm] && realms[currentRealm].scrollHeight || 0 -}) - -virtualListStore.compute('offsetHeight', ['currentRealm', 'realms'], (currentRealm, realms) => { - return realms[currentRealm] && realms[currentRealm].offsetHeight || 0 -}) +virtualListStore.computeForRealm('items', []) +virtualListStore.computeForRealm('showFooter', false) +virtualListStore.computeForRealm('scrollTop', 0) +virtualListStore.computeForRealm('scrollHeight', 0) +virtualListStore.computeForRealm('offsetHeight', 0) virtualListStore.compute('visibleItems', ['items', 'scrollTop', 'itemHeights', 'offsetHeight'], diff --git a/routes/_utils/RealmStore.js b/routes/_utils/RealmStore.js new file mode 100644 index 00000000..de0a55fa --- /dev/null +++ b/routes/_utils/RealmStore.js @@ -0,0 +1,32 @@ +// A store where you can divide data into "realms" that are backed with an LRU cache. +// Each realm has self-contained data that you can set with setForRealm() and compute +// with computeForRealm(). The maxSize determines how many realms to keep in the LRU cache. +import { Store } from 'svelte/store.js' +import QuickLRU from 'quick-lru' + +export class RealmStore extends Store { + constructor(init, maxSize) { + super(init) + this.set({realms: new QuickLRU({maxSize: maxSize})}) + } + + setCurrentRealm(realm) { + this.set({currentRealm: realm}) + } + + setForRealm(obj) { + let realmName = this.get('currentRealm') + let realms = this.get('realms') + realms.set(realmName, Object.assign(realms.get(realmName) || {}, obj)) + this.set({realms: realms}) + } + + computeForRealm(key, defaultValue) { + this.compute(key, + ['realms', 'currentRealm'], + (realms, currentRealm) => { + let realmData = realms.get(currentRealm) + return (realmData && realmData[key]) || defaultValue + }) + } +} \ No newline at end of file