itemHeights should be divided by realm

This commit is contained in:
Nolan Lawson 2018-01-31 08:37:59 -08:00
parent 0d4ee2bba3
commit 2c2f84b870
4 changed files with 46 additions and 37 deletions

View file

@ -19,7 +19,7 @@
const asyncLayout = new AsyncLayout(() => '__footer__') const asyncLayout = new AsyncLayout(() => '__footer__')
asyncLayout.observe('__footer__', this.refs.node, (rect) => { asyncLayout.observe('__footer__', this.refs.node, (rect) => {
asyncLayout.disconnect() asyncLayout.disconnect()
this.store.set({footerHeight: rect.height}) this.store.setForRealm({footerHeight: rect.height})
}) })
}, },
store: () => virtualListStore, store: () => virtualListStore,

View file

@ -5,7 +5,7 @@
<:Component {component} <:Component {component}
virtualProps="{{props}}" virtualProps="{{props}}"
virtualIndex="{{index}}" virtualIndex="{{index}}"
virtualLength="{{$numItems}}" virtualLength="{{numItems}}"
on:recalculateHeight="doRecalculateHeight()"/> on:recalculateHeight="doRecalculateHeight()"/>
</div> </div>
<style> <style>
@ -39,7 +39,7 @@
asyncLayout.observe(key, this.refs.node, (rect) => { asyncLayout.observe(key, this.refs.node, (rect) => {
asyncLayout.disconnect() asyncLayout.disconnect()
// update all item heights in one batch for better perf // update all item heights in one batch for better perf
this.store.batchUpdate('itemHeights', key, rect.height) this.store.batchUpdateForRealm('itemHeights', key, rect.height)
}) })
} }
} }

View file

@ -6,49 +6,18 @@ const VIEWPORT_RENDER_FACTOR = 4
class VirtualListStore extends RealmStore { class VirtualListStore extends RealmStore {
constructor(state) { constructor(state) {
super(state, /* maxSize */ 10) super(state, /* maxSize */ 10)
this._batches = {}
}
batchUpdate(key, subKey, value) {
let batch = this._batches[key]
if (!batch) {
batch = this._batches[key] = {}
}
batch[subKey] = value
requestAnimationFrame(() => {
let batch = this._batches[key]
if (!batch) {
return
}
let updatedKeys = Object.keys(batch)
if (!updatedKeys.length) {
return
}
mark('batchUpdate()')
let obj = this.get(key)
for (let otherKey of updatedKeys) {
obj[otherKey] = batch[otherKey]
}
delete this._batches[key]
let toSet = {}
toSet[key] = obj
this.set(toSet)
stop('batchUpdate()')
})
} }
} }
const virtualListStore = new VirtualListStore({ const virtualListStore = new VirtualListStore()
itemHeights: {},
footerHeight: 0
})
virtualListStore.computeForRealm('items', []) virtualListStore.computeForRealm('items', [])
virtualListStore.computeForRealm('showFooter', false) virtualListStore.computeForRealm('showFooter', false)
virtualListStore.computeForRealm('footerHeight', 0)
virtualListStore.computeForRealm('scrollTop', 0) virtualListStore.computeForRealm('scrollTop', 0)
virtualListStore.computeForRealm('scrollHeight', 0) virtualListStore.computeForRealm('scrollHeight', 0)
virtualListStore.computeForRealm('offsetHeight', 0) virtualListStore.computeForRealm('offsetHeight', 0)
virtualListStore.computeForRealm('itemHeights', {})
virtualListStore.compute('visibleItems', virtualListStore.compute('visibleItems',
['items', 'scrollTop', 'itemHeights', 'offsetHeight'], ['items', 'scrollTop', 'itemHeights', 'offsetHeight'],

View file

@ -3,11 +3,13 @@
// with computeForRealm(). The maxSize determines how many realms to keep in the LRU cache. // with computeForRealm(). The maxSize determines how many realms to keep in the LRU cache.
import { Store } from 'svelte/store.js' import { Store } from 'svelte/store.js'
import QuickLRU from 'quick-lru' import QuickLRU from 'quick-lru'
import { mark, stop } from './marks'
export class RealmStore extends Store { export class RealmStore extends Store {
constructor(init, maxSize) { constructor(init, maxSize) {
super(init) super(init)
this.set({realms: new QuickLRU({maxSize: maxSize})}) this.set({realms: new QuickLRU({maxSize: maxSize})})
this._batches = {}
} }
setCurrentRealm(realm) { setCurrentRealm(realm) {
@ -29,4 +31,42 @@ export class RealmStore extends Store {
return (realmData && realmData[key]) || defaultValue return (realmData && realmData[key]) || defaultValue
}) })
} }
/*
* Update several values at once in a realm, assuming the key points
* to a plain old javascript object.
*/
batchUpdateForRealm(key, subKey, value) {
let realm = this.get('currentRealm')
let realmBatches = this._batches[realm]
if (!realmBatches) {
realmBatches = this._batches[realm] = {}
}
let batch = realmBatches[key]
if (!batch) {
batch = realmBatches[key] = {}
}
batch[subKey] = value
requestAnimationFrame(() => {
let batch = this._batches[realm] && this._batches[realm][key]
if (!batch) {
return
}
let updatedKeys = Object.keys(batch)
if (!updatedKeys.length) {
return
}
mark('batchUpdate')
let obj = this.get(key)
for (let otherKey of updatedKeys) {
obj[otherKey] = batch[otherKey]
}
delete this._batches[realm][key]
let realms = this.get('realms')
realms.set(realm, Object.assign(realms.get(realm) || {}, {[key]: obj}))
this.set({realms: realms})
stop('batchUpdate')
})
}
} }