forked from cybrespace/pinafore
		
	itemHeights should be divided by realm
This commit is contained in:
		
							parent
							
								
									0d4ee2bba3
								
							
						
					
					
						commit
						2c2f84b870
					
				
					 4 changed files with 46 additions and 37 deletions
				
			
		|  | @ -19,7 +19,7 @@ | |||
|       const asyncLayout = new AsyncLayout(() => '__footer__') | ||||
|       asyncLayout.observe('__footer__', this.refs.node, (rect) => { | ||||
|         asyncLayout.disconnect() | ||||
|         this.store.set({footerHeight: rect.height}) | ||||
|         this.store.setForRealm({footerHeight: rect.height}) | ||||
|       }) | ||||
|     }, | ||||
|     store: () => virtualListStore, | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
|   <:Component {component} | ||||
|               virtualProps="{{props}}" | ||||
|               virtualIndex="{{index}}" | ||||
|               virtualLength="{{$numItems}}" | ||||
|               virtualLength="{{numItems}}" | ||||
|               on:recalculateHeight="doRecalculateHeight()"/> | ||||
| </div> | ||||
| <style> | ||||
|  | @ -39,7 +39,7 @@ | |||
|         asyncLayout.observe(key, this.refs.node, (rect) => { | ||||
|           asyncLayout.disconnect() | ||||
|           // update all item heights in one batch for better perf | ||||
|           this.store.batchUpdate('itemHeights', key, rect.height) | ||||
|           this.store.batchUpdateForRealm('itemHeights', key, rect.height) | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|  |  | |||
|  | @ -6,49 +6,18 @@ const VIEWPORT_RENDER_FACTOR = 4 | |||
| class VirtualListStore extends RealmStore { | ||||
|   constructor(state) { | ||||
|     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({ | ||||
|   itemHeights: {}, | ||||
|   footerHeight: 0 | ||||
| }) | ||||
| const virtualListStore = new VirtualListStore() | ||||
| 
 | ||||
| virtualListStore.computeForRealm('items', []) | ||||
| virtualListStore.computeForRealm('showFooter', false) | ||||
| virtualListStore.computeForRealm('footerHeight', 0) | ||||
| virtualListStore.computeForRealm('scrollTop', 0) | ||||
| virtualListStore.computeForRealm('scrollHeight', 0) | ||||
| virtualListStore.computeForRealm('offsetHeight', 0) | ||||
| virtualListStore.computeForRealm('itemHeights', {}) | ||||
| 
 | ||||
| virtualListStore.compute('visibleItems', | ||||
|     ['items', 'scrollTop', 'itemHeights', 'offsetHeight'], | ||||
|  |  | |||
|  | @ -3,11 +3,13 @@ | |||
| // 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' | ||||
| import { mark, stop } from './marks' | ||||
| 
 | ||||
| export class RealmStore extends Store { | ||||
|   constructor(init, maxSize) { | ||||
|     super(init) | ||||
|     this.set({realms: new QuickLRU({maxSize: maxSize})}) | ||||
|     this._batches = {} | ||||
|   } | ||||
| 
 | ||||
|   setCurrentRealm(realm) { | ||||
|  | @ -29,4 +31,42 @@ export class RealmStore extends Store { | |||
|       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') | ||||
|     }) | ||||
|   } | ||||
| } | ||||
		Loading…
	
	Add table
		
		Reference in a new issue