refactor virtual store to use realms

This commit is contained in:
Nolan Lawson 2018-01-27 08:13:28 -08:00
parent 610e54469e
commit 687cc5c961
11 changed files with 49 additions and 75 deletions

View file

@ -1,7 +1,7 @@
<Nav :page :dynamicPage :dynamicHref :dynamicIcon :dynamicLabel/>
{{#if virtual}}
<VirtualListContainer storeKey="{{virtualStoreKey}}">
<VirtualListContainer realm="{{virtualRealm}}">
<main>
<slot></slot>
</main>

View file

@ -7,7 +7,7 @@
shown="{{initialized}}"
footerComponent="{{LoadingFooter}}"
showFooter="{{initialized && runningUpdate}}"
storeKey="{{timeline}}"
realm="{{timeline}}"
on:initializedVisibleItems="initialize()"
/>
</div>

View file

@ -31,13 +31,11 @@
export default {
oncreate () {
this.observe('showFooter', showFooter => {
this.store.set({showFooter: showFooter})
this.store.setForRealm({showFooter: showFooter})
})
this.observe('items', (items) => {
mark('set items')
this.store.set({
items: items
})
this.store.setForRealm({items: items})
stop('set items')
this.fireScrollToBottom = throttle(() => {
this.fire('scrollToBottom')

View file

@ -13,73 +13,38 @@
const SCROLL_EVENT_DELAY = 300
const cachedVirtualStores = {}
if (process.browser && process.env.NODE_ENV !== 'production') {
window.cachedVirtualStores = cachedVirtualStores
}
export default {
oncreate() {
mark('onCreate VirtualListContainer')
let node = this.refs.node
let storeKey = this.get('storeKey')
let cachedStore
if (storeKey && (cachedStore = cachedVirtualStores[storeKey])) {
this.store.set({
scrollTop: cachedStore.state.scrollTop,
scrollHeight: cachedStore.state.scrollHeight,
offsetHeight: cachedStore.state.offsetHeight
})
this.store.set(cachedStore.state)
// rehydrate scroll top
let cachedScrollTop = cachedStore.state.scrollTop || 0
if (cachedScrollTop === 0) {
if (process.env.NODE_ENV !== 'production') {
console.log('no need to force scroll top')
}
return
}
let initializedScrollTop = false
let node = this.refs.node
let realm = this.get('realm')
this.store.set({currentRealm: realm})
let scrollTop = this.store.get('scrollTop')
if (scrollTop > 0) {
this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => {
if (process.env.NODE_ENV !== 'production') {
console.log('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight)
}
if (!initializedScrollTop && allVisibleItemsHaveHeight && node) {
initializedScrollTop = true
if (!this.get('initializedScrollTop') && allVisibleItemsHaveHeight && node) {
this.set({'initializedScrollTop': true})
requestAnimationFrame(() => {
mark('set scrollTop')
if (process.env.NODE_ENV !== 'production') {
console.log('forcing scroll top to ', cachedScrollTop)
console.log('forcing scroll top to ', scrollTop)
}
node.scrollTop = cachedScrollTop
node.scrollTop = scrollTop
stop('set scrollTop')
})
}
})
} else {
this.store.set({
scrollTop: 0,
this.store.setForRealm({
scrollHeight: node.scrollHeight,
offsetHeight: node.offsetHeight
})
}
stop('onCreate VirtualListContainer')
},
ondestroy() {
let storeKey = this.get('storeKey')
if (storeKey) {
let clonedState = this.store.cloneState()
if (process.env.NODE_ENV !== 'production') {
console.log('caching scroll top', clonedState.scrollTop)
}
cachedVirtualStores[storeKey] = {
state: clonedState
}
}
},
store: () => virtualListStore,
events: {
scroll(node, callback) {
@ -116,7 +81,7 @@
},
methods: {
onScroll(event) {
this.store.set({
this.store.setForRealm({
scrollTop: event.target.scrollTop,
scrollHeight: event.target.scrollHeight
})

View file

@ -3,28 +3,12 @@ import { mark, stop } from '../../_utils/marks'
const VIEWPORT_RENDER_FACTOR = 4
const cloneKeys = [
'items',
'itemHeights',
'scrollTop',
'scrollHeight',
'offsetHeight'
]
class VirtualListStore extends Store {
constructor(state) {
super(state)
this._batches = {}
}
cloneState() {
let res = {}
for (let key of cloneKeys) {
res[key] = this.get(key)
}
return res
}
batchUpdate(key, subKey, value) {
let batch = this._batches[key]
if (!batch) {
@ -53,15 +37,42 @@ 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({
items: [],
realms: {},
currentRealm: null,
itemHeights: {},
showFooter: false,
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.compute('visibleItems',
['items', 'scrollTop', 'itemHeights', 'offsetHeight'],
(items, scrollTop, itemHeights, offsetHeight) => {

View file

@ -4,7 +4,7 @@
<Layout page='tags'
virtual="true"
virtualStoreKey='account/{{params.accountId}}'
virtualRealm='account/{{params.accountId}}'
dynamicPage="{{profileName}}"
dynamicHref="/accounts/{{params.accountId}}"
dynamicLabel="{{shortProfileName}}"

View file

@ -2,7 +2,7 @@
<title>Pinafore Federated</title>
</:Head>
<Layout page='federated' virtual="true" virtualStoreKey="federated">
<Layout page='federated' virtual="true" virtualRealm="federated">
{{#if $isUserLoggedIn}}
<LazyTimeline timeline='federated' />
{{else}}

View file

@ -2,7 +2,7 @@
<title>Pinafore Home</title>
</:Head>
<Layout page='home' virtual="true" virtualStoreKey="home">
<Layout page='home' virtual="true" virtualRealm="home">
{{#if $isUserLoggedIn}}
<LazyTimeline timeline='home' />
{{else}}

View file

@ -2,7 +2,7 @@
<title>Pinafore Local</title>
</:Head>
<Layout page='local' virtual="true" virtualStoreKey="local">
<Layout page='local' virtual="true" virtualRealm="local">
{{#if $isUserLoggedIn}}
<LazyTimeline timeline='local' />
{{else}}

View file

@ -2,7 +2,7 @@
<title>Pinafore Notifications</title>
</:Head>
<Layout page='notifications' virtual="true" virtualStoreKey="federated">
<Layout page='notifications' virtual="true" virtualRealm="federated">
<HiddenFromSSR>
<FreeTextLayout>
<h1>Notifications</h1>

View file

@ -4,7 +4,7 @@
<Layout page='tags'
virtual="true"
virtualStoreKey='tag/{{params.tagName}}'
virtualRealm='tag/{{params.tagName}}'
dynamicPage="{{params.tagName}}"
dynamicHref="/tags/{{params.tagName}}"
dynamicLabel="{{'#' + params.tagName}}"