@infinite-list/data-model
Advanced tools
Comparing version 0.2.4 to 0.2.5
@@ -17,3 +17,3 @@ export declare const DEFAULT_LAYOUT: { | ||
export declare function shallowDiffers(prev: Object, next: Object): boolean; | ||
export declare const isNotEmpty: (obj: any) => boolean; | ||
export declare const isEmpty: (obj: any) => boolean; | ||
export declare const buildStateTokenIndexKey: (startIndex: number, endIndex: number) => string; |
@@ -22,2 +22,3 @@ import ItemMeta from './ItemMeta'; | ||
getReflowItemsLength(): 1 | 0; | ||
hasUnLayoutItems(): boolean; | ||
getTotalLength(): number | "invalid_length"; | ||
@@ -24,0 +25,0 @@ getIgnoredToPerBatch(): boolean; |
@@ -5,3 +5,3 @@ export { default as ItemsDimensions } from './ItemsDimensions'; | ||
export { default as PseudoListDimensions } from './PseudoListDimensions'; | ||
export { ListDimensionsProps } from './types/Dimensions.types'; | ||
export * from './types/Dimensions.types'; | ||
export { default as ItemMeta } from './ItemMeta'; | ||
@@ -8,0 +8,0 @@ export { default as ListSpyUtils } from './utils/ListSpyUtils'; |
@@ -44,2 +44,3 @@ import Batchinator from '@x-oasis/batchinator'; | ||
get stateResult(): ListStateResult<ItemT>; | ||
set scrollMetrics(scrollMetrics: ScrollMetrics); | ||
set offsetInListGroup(offset: number); | ||
@@ -50,2 +51,3 @@ get state(): ListState<ItemT>; | ||
getRenderState(): ListRenderState; | ||
setRenderState(state: ListRenderState): void; | ||
setRenderStateFinished(): ListRenderState; | ||
@@ -67,2 +69,3 @@ setActive(): void; | ||
resetIntervalTree(): PrefixIntervalTree; | ||
hasUnLayoutItems(): boolean; | ||
_recycleEnabled(): boolean; | ||
@@ -69,0 +72,0 @@ recalculateRecycleResultState(): void; |
@@ -66,2 +66,3 @@ import Batchinator from '@x-oasis/batchinator'; | ||
getReflowItemsLength(): number; | ||
hasUnLayoutItems(): boolean; | ||
calculateReflowItemsLength(): void; | ||
@@ -68,0 +69,0 @@ getConfigTuple(): ViewabilityConfigTuples; |
@@ -14,3 +14,3 @@ import Batchinator from '@x-oasis/batchinator'; | ||
setHandler(onEndReached: OnEndReached): void; | ||
perform(scrollMetrics: ScrollMetrics): { | ||
perform(scrollMetrics: ScrollMetrics, positive?: boolean): { | ||
distanceFromEnd: number; | ||
@@ -17,0 +17,0 @@ isEndReached: boolean; |
{ | ||
"name": "@infinite-list/data-model", | ||
"version": "0.2.4", | ||
"version": "0.2.5", | ||
"files": [ | ||
@@ -5,0 +5,0 @@ "dist", |
import createStore from '../state/createStore'; | ||
import ListDimensions from '../ListDimensions'; | ||
import ListGroupDimensions from '../ListGroupDimensions'; | ||
@@ -470,2 +471,554 @@ import Batchinator from '@x-oasis/batchinator'; | ||
}); | ||
it('if visibleStartIndex and visibleEndIndex not change, then return directly', () => { | ||
const data = buildData(100); | ||
const list = new ListDimensions({ | ||
data: [], | ||
id: 'list_group', | ||
keyExtractor: defaultKeyExtractor, | ||
maxToRenderPerBatch: 7, | ||
windowSize: 2, | ||
initialNumToRender: 4, | ||
onEndReachedThreshold: 2, | ||
getContainerLayout: () => ({ | ||
x: 0, | ||
y: 0, | ||
width: 375, | ||
height: 2000, | ||
}), | ||
viewabilityConfigCallbackPairs: [ | ||
{ | ||
viewabilityConfig: { | ||
viewport: 1, | ||
name: 'imageViewable', | ||
viewAreaCoveragePercentThreshold: 20, | ||
}, | ||
}, | ||
{ | ||
viewabilityConfig: { | ||
name: 'viewable', | ||
viewAreaCoveragePercentThreshold: 30, | ||
}, | ||
}, | ||
], | ||
}); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: -1, | ||
visibleEndIndex: -1, | ||
bufferedStartIndex: -1, | ||
bufferedEndIndex: -1, | ||
isEndReached: false, | ||
distanceFromEnd: 0, | ||
data: [], | ||
actionType: 'initial', | ||
}); | ||
list.setData(data); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 0, | ||
visibleEndIndex: 3, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 3, | ||
isEndReached: false, | ||
distanceFromEnd: 0, | ||
data: data.slice(0, 4), | ||
actionType: 'initial', | ||
}); | ||
list.setKeyItemLayout('3', 100); | ||
// @ts-ignore | ||
list.updateScrollMetrics({ | ||
offset: 0, | ||
visibleLength: 926, | ||
contentLength: 1000, | ||
}); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 0, | ||
visibleEndIndex: 3, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 7, | ||
isEndReached: true, | ||
distanceFromEnd: 74, | ||
data: data.slice(0, 8), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
// @ts-ignore | ||
list.updateScrollMetrics({ | ||
offset: 0, | ||
visibleLength: 926, | ||
contentLength: 1000, | ||
}); | ||
const listState = list.state; | ||
expect(listState).toEqual({ | ||
visibleStartIndex: 0, | ||
visibleEndIndex: 3, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 7, | ||
isEndReached: true, | ||
distanceFromEnd: 74, | ||
data: data.slice(0, 8), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
// @ts-ignore | ||
list.updateScrollMetrics({ | ||
offset: 0, | ||
visibleLength: 926, | ||
contentLength: 1001, | ||
}); | ||
expect(list.state).toBe(listState); | ||
}); | ||
}); | ||
describe('resolveUnLayoutLimitation', () => { | ||
it('the max unLayout item should be not greater than `maxToRenderPerBatch`', () => { | ||
const data = buildData(100); | ||
const list = new ListDimensions({ | ||
data: [], | ||
id: 'list_group', | ||
keyExtractor: defaultKeyExtractor, | ||
maxToRenderPerBatch: 7, | ||
windowSize: 2, | ||
initialNumToRender: 4, | ||
onEndReachedThreshold: 2, | ||
getContainerLayout: () => ({ | ||
x: 0, | ||
y: 0, | ||
width: 375, | ||
height: 2000, | ||
}), | ||
}); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: -1, | ||
visibleEndIndex: -1, | ||
bufferedStartIndex: -1, | ||
bufferedEndIndex: -1, | ||
isEndReached: false, | ||
distanceFromEnd: 0, | ||
data: [], | ||
actionType: 'initial', | ||
}); | ||
list.setData(data); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 0, | ||
visibleEndIndex: 3, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 3, | ||
isEndReached: false, | ||
distanceFromEnd: 0, | ||
data: data.slice(0, 4), | ||
actionType: 'initial', | ||
}); | ||
list.setKeyItemLayout('3', 100); | ||
// @ts-ignore | ||
list.updateScrollMetrics({ | ||
offset: 0, | ||
visibleLength: 926, | ||
contentLength: 1000, | ||
}); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 0, | ||
visibleEndIndex: 3, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 7, | ||
isEndReached: true, | ||
distanceFromEnd: 74, | ||
data: data.slice(0, 8), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
list.setKeyItemLayout('4', 100); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 0, | ||
visibleLength: 926, | ||
contentLength: 1000, | ||
}, | ||
false | ||
); | ||
const listState = list.state; | ||
expect(listState).toEqual({ | ||
visibleStartIndex: 0, | ||
visibleEndIndex: 4, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 8, | ||
isEndReached: true, | ||
distanceFromEnd: 74, | ||
data: data.slice(0, 9), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 100, | ||
visibleLength: 926, | ||
contentLength: 1000, | ||
}, | ||
false | ||
); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 3, | ||
visibleEndIndex: 4, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 11, | ||
isEndReached: true, | ||
distanceFromEnd: -26, | ||
data: data.slice(0, 12), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
}); | ||
}); | ||
describe('Has trailing element', () => { | ||
it('rewrite onEndReached', () => { | ||
const data = buildData(30); | ||
const list = new ListDimensions({ | ||
data, | ||
id: 'list_group', | ||
keyExtractor: defaultKeyExtractor, | ||
maxToRenderPerBatch: 7, | ||
windowSize: 2, | ||
initialNumToRender: 4, | ||
onEndReachedThreshold: 2, | ||
getContainerLayout: () => ({ | ||
x: 0, | ||
y: 0, | ||
width: 375, | ||
height: 2000, | ||
}), | ||
}); | ||
list.setKeyItemLayout('1', 100); | ||
list.setKeyItemLayout('2', 100); | ||
list.setKeyItemLayout('3', 100); | ||
list.setKeyItemLayout('4', 100); | ||
list.setKeyItemLayout('5', 100); | ||
list.setKeyItemLayout('6', 100); | ||
list.setKeyItemLayout('7', 100); | ||
list.setKeyItemLayout('8', 100); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 100, | ||
visibleLength: 926, | ||
contentLength: 4000, | ||
}, | ||
false | ||
); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 1, | ||
visibleEndIndex: 8, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 15, | ||
isEndReached: true, | ||
distanceFromEnd: 2974, | ||
data: data.slice(0, 16), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 1500, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
let listState = list.state; | ||
expect(listState).toEqual({ | ||
visibleStartIndex: 8, | ||
visibleEndIndex: 8, | ||
bufferedStartIndex: 6, | ||
bufferedEndIndex: 15, | ||
isEndReached: true, | ||
distanceFromEnd: 3574, | ||
data: data.slice(0, 16), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 1500, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
expect(list.state).toBe(listState); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 3000, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 8, | ||
visibleEndIndex: 8, | ||
bufferedStartIndex: 8, | ||
bufferedEndIndex: 15, | ||
isEndReached: true, | ||
distanceFromEnd: 2074, | ||
data: data.slice(0, 16), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
list.setKeyItemLayout('29', 100); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 3010, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
listState = list.state; | ||
expect(listState).toEqual({ | ||
visibleStartIndex: 29, | ||
visibleEndIndex: 29, | ||
bufferedStartIndex: 29, | ||
bufferedEndIndex: 29, | ||
isEndReached: false, | ||
distanceFromEnd: 2064, | ||
data: data.slice(0, 30), | ||
actionType: 'recalculate', | ||
}); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 3500, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 29, | ||
visibleEndIndex: 29, | ||
bufferedStartIndex: 29, | ||
bufferedEndIndex: 29, | ||
isEndReached: false, | ||
distanceFromEnd: 2064, | ||
data: data.slice(0, 30), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 1000, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 29, | ||
visibleEndIndex: 29, | ||
bufferedStartIndex: 29, | ||
bufferedEndIndex: 29, | ||
isEndReached: false, | ||
distanceFromEnd: 2064, | ||
data: data.slice(0, 30), | ||
actionType: 'recalculate', | ||
}); | ||
}); | ||
}); | ||
describe('Has heading element', () => { | ||
it('rewrite onEndReached', () => { | ||
const data = buildData(30); | ||
const list = new ListDimensions({ | ||
data, | ||
id: 'list_group', | ||
keyExtractor: defaultKeyExtractor, | ||
maxToRenderPerBatch: 7, | ||
windowSize: 2, | ||
initialNumToRender: 4, | ||
onEndReachedThreshold: 2, | ||
getContainerLayout: () => ({ | ||
x: 0, | ||
y: 3000, | ||
width: 375, | ||
height: 2000, | ||
}), | ||
}); | ||
list.setKeyItemLayout('1', 100); | ||
list.setKeyItemLayout('2', 100); | ||
list.setKeyItemLayout('3', 100); | ||
list.setKeyItemLayout('4', 100); | ||
list.setKeyItemLayout('5', 100); | ||
list.setKeyItemLayout('6', 100); | ||
list.setKeyItemLayout('7', 100); | ||
list.setKeyItemLayout('8', 100); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 100, | ||
visibleLength: 926, | ||
contentLength: 4000, | ||
}, | ||
false | ||
); | ||
let listState = list.state; | ||
expect(listState).toEqual({ | ||
visibleStartIndex: -1, | ||
visibleEndIndex: -1, | ||
bufferedStartIndex: -1, | ||
bufferedEndIndex: -1, | ||
isEndReached: false, | ||
distanceFromEnd: 2974, | ||
data: data.slice(0, 9), | ||
actionType: 'recalculate', | ||
}); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 1500, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
expect(listState).toBe(list.state); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 1500, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
expect(list.state).toBe(listState); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 3000, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 0, | ||
visibleEndIndex: 8, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 8, | ||
isEndReached: false, | ||
distanceFromEnd: 2074, | ||
data: data.slice(0, 9), | ||
actionType: 'recalculate', | ||
}); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 3010, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
listState = list.state; | ||
expect(listState).toEqual({ | ||
visibleStartIndex: 1, | ||
visibleEndIndex: 8, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 15, | ||
isEndReached: true, | ||
distanceFromEnd: 2064, | ||
data: data.slice(0, 16), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
list.setKeyItemLayout('29', 100); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 3500, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
// TODO xxxxxxxxxx | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: 5, | ||
visibleEndIndex: 29, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 15, | ||
isEndReached: true, | ||
distanceFromEnd: 1574, | ||
data: data.slice(0, 30), | ||
actionType: 'hydrationWithBatchUpdate', | ||
}); | ||
list.updateScrollMetrics( | ||
// @ts-ignore | ||
{ | ||
offset: 1000, | ||
visibleLength: 926, | ||
contentLength: 6000, | ||
}, | ||
false | ||
); | ||
expect(list.state).toEqual({ | ||
visibleStartIndex: -1, | ||
visibleEndIndex: -1, | ||
bufferedStartIndex: 0, | ||
bufferedEndIndex: 15, | ||
isEndReached: false, | ||
distanceFromEnd: 4074, | ||
data: data.slice(0, 30), | ||
actionType: 'recalculate', | ||
}); | ||
}); | ||
}); |
@@ -40,7 +40,7 @@ export const DEFAULT_LAYOUT = { | ||
export const isNotEmpty = (obj: any) => { | ||
export const isEmpty = (obj: any) => { | ||
if (Object.prototype.toString.call(obj) === '[object Object]') { | ||
return !!Object.keys.length; | ||
return !Object.keys.length; | ||
} | ||
return false; | ||
return true; | ||
}; | ||
@@ -47,0 +47,0 @@ |
import ItemMeta from './ItemMeta'; | ||
import ListGroupDimensions from './ListGroupDimensions'; | ||
import { INVALID_LENGTH } from './common'; | ||
import layoutEqual from '@x-oasis/layout-equal' | ||
import layoutEqual from '@x-oasis/layout-equal'; | ||
import SelectValue, { | ||
@@ -74,2 +74,7 @@ selectHorizontalValue, | ||
hasUnLayoutItems() { | ||
const meta = this.getMeta(); | ||
return !!meta?.getLayout(); | ||
} | ||
getTotalLength() { | ||
@@ -156,3 +161,3 @@ const meta = this.getMeta(); | ||
if (typeof layout === 'number') { | ||
let length = layout; | ||
const length = layout; | ||
if (this._selectValue.selectLength(meta.getLayout() || {}) !== length) { | ||
@@ -172,3 +177,3 @@ this._selectValue.setLength(meta.ensureLayout(), length); | ||
meta.setLayout(layout as ItemLayout); | ||
let length = this._selectValue.selectLength(layout as ItemLayout); | ||
const length = this._selectValue.selectLength(layout as ItemLayout); | ||
if (_update) { | ||
@@ -175,0 +180,0 @@ if (this._listGroupDimension) { |
@@ -5,3 +5,3 @@ export { default as ItemsDimensions } from './ItemsDimensions'; | ||
export { default as PseudoListDimensions } from './PseudoListDimensions'; | ||
export { ListDimensionsProps } from './types/Dimensions.types'; | ||
export * from './types/Dimensions.types'; | ||
export { default as ItemMeta } from './ItemMeta'; | ||
@@ -8,0 +8,0 @@ export { default as ListSpyUtils } from './utils/ListSpyUtils'; |
@@ -12,3 +12,3 @@ import noop from '@x-oasis/noop'; | ||
INVALID_LENGTH, | ||
isNotEmpty, | ||
isEmpty, | ||
shallowDiffers, | ||
@@ -223,2 +223,6 @@ buildStateTokenIndexKey, | ||
set scrollMetrics(scrollMetrics: ScrollMetrics) { | ||
this._scrollMetrics = scrollMetrics; | ||
} | ||
set offsetInListGroup(offset: number) { | ||
@@ -264,2 +268,6 @@ this._offsetInListGroup = offset; | ||
setRenderState(state: ListRenderState) { | ||
this._renderState = state; | ||
} | ||
setRenderStateFinished() { | ||
@@ -386,2 +394,6 @@ return (this._renderState = ListRenderState.ON_RENDER_FINISHED); | ||
hasUnLayoutItems() { | ||
return this.getReflowItemsLength() < this._data.length; | ||
} | ||
_recycleEnabled() { | ||
@@ -398,2 +410,6 @@ if (this.fillingMode !== FillingMode.RECYCLE) return false; | ||
// 变了,那么就去更新 | ||
/** | ||
* In RN, layout change will not trigger `updateScrollMetrics`, because it's replaced with | ||
* onContentSizeChanged. | ||
*/ | ||
setIntervalTreeValue(index: number, length: number) { | ||
@@ -435,4 +451,2 @@ const oldLength = this.intervalTree.getHeap()[1]; | ||
this.setRenderStateFinished(); | ||
this._renderStateListeners.forEach((listener) => listener()); | ||
this._renderStateListeners = []; | ||
} | ||
@@ -577,2 +591,5 @@ | ||
/** | ||
* Data change will trigger `state` update for one times. | ||
*/ | ||
setData(data: Array<ItemT>) { | ||
@@ -717,3 +734,3 @@ if (!this._isActive) { | ||
const len = data.length; | ||
let updateIntervalTree = true; | ||
for (let index = 0; index < len; index++) { | ||
@@ -727,10 +744,10 @@ const item = data[index]; | ||
if (meta.getLayout() && updateIntervalTree) { | ||
if (meta.getLayout()) { | ||
const itemLength = this._selectValue.selectLength(meta.getLayout()); | ||
const separatorLength = meta.getSeparatorLength(); | ||
// 最后一个不包含separatorLength | ||
const length = | ||
currentIndex === len - 1 ? itemLength : itemLength + separatorLength; | ||
index === len - 1 ? itemLength : itemLength + separatorLength; | ||
intervalTree.set(currentIndex, length); | ||
} else { | ||
updateIntervalTree = false; | ||
} | ||
@@ -945,3 +962,2 @@ | ||
// 只有当recycleEnabled为true的时候,才进行位置替换 | ||
if (recycleEnabled) { | ||
@@ -965,3 +981,3 @@ if (visibleEndIndex >= 0) { | ||
let index = visibleStartIndex, size = beforeSize; | ||
size > 0 && index >= 0; | ||
size > 0 && index >= 0 && index >= bufferedStartIndex; | ||
size--, index-- | ||
@@ -1005,3 +1021,2 @@ ) { | ||
const itemMeta = this.getItemMeta(item, targetIndex); | ||
const itemLayout = itemMeta?.getLayout(); | ||
@@ -1244,7 +1259,3 @@ const itemLength = | ||
updateState( | ||
newState: PreStateResult, | ||
scrollMetrics: ScrollMetrics | ||
// performItemsMetaChange = true | ||
) { | ||
updateState(newState: PreStateResult, scrollMetrics: ScrollMetrics) { | ||
const { | ||
@@ -1291,3 +1302,3 @@ bufferedStartIndex: nextBufferedStartIndex, | ||
if (!isNotEmpty(state)) return; | ||
if (isEmpty(state)) return; | ||
this.updateState(state, scrollMetrics); | ||
@@ -1315,6 +1326,6 @@ const { isEndReached, distanceFromEnd } = state; | ||
* - on scroll | ||
* - layout change. In rn, use contentSizeChanged. in web, maybe `_setKeyItemLayout` | ||
* to trigger state updating.. | ||
* - layout change. | ||
* - In rn, use contentSizeChanged. `setIntervalTreeValue` has remove update scroll logic. | ||
* - In web, maybe `setIntervalTreeValue` to trigger state updating.. | ||
*/ | ||
updateScrollMetrics( | ||
@@ -1321,0 +1332,0 @@ scrollMetrics: ScrollMetrics = this._scrollMetrics, |
@@ -13,3 +13,3 @@ import Batchinator from '@x-oasis/batchinator'; | ||
import ListDimensions from './ListDimensions'; | ||
import { isNotEmpty } from './common'; | ||
import { isEmpty } from './common'; | ||
import ViewabilityConfigTuples from './viewable/ViewabilityConfigTuples'; | ||
@@ -239,2 +239,15 @@ import manager from './manager'; | ||
hasUnLayoutItems() { | ||
const len = this.indexKeys.length; | ||
for (let index = 0; index < len; index++) { | ||
const key = this.indexKeys[index]; | ||
const dimensions = this.getDimension(key); | ||
if (dimensions && dimensions?.hasUnLayoutItems()) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
calculateReflowItemsLength() { | ||
@@ -946,3 +959,3 @@ this._reflowItemsLength = this.indexKeys.reduce((acc, cur) => { | ||
if (!isNotEmpty(state)) return; | ||
if (isEmpty(state)) return; | ||
@@ -949,0 +962,0 @@ const bufferedMetaRanges = this.computeIndexRangeMeta({ |
import ListDimensions from '../ListDimensions'; | ||
import { INVALID_LENGTH } from '../common'; | ||
import { ScrollMetrics } from '../types'; | ||
@@ -15,6 +16,22 @@ import { Action, ActionType, ReducerResult } from './types'; | ||
const { isEndReached, distanceFromEnd } = dimension | ||
.getOnEndReachedHelper() | ||
.perform(scrollMetrics); | ||
const _info = dimension.getOnEndReachedHelper().perform(scrollMetrics); | ||
let isEndReached = _info.isEndReached; | ||
const distanceFromEnd = _info.distanceFromEnd; | ||
if (!isEndReached) { | ||
const { visibleEndIndex, visibleStartIndex } = state; | ||
const total = dimension.getTotalLength(); | ||
if ( | ||
(visibleStartIndex !== -1 || visibleEndIndex !== -1) && | ||
total !== INVALID_LENGTH && | ||
dimension.hasUnLayoutItems() | ||
) { | ||
isEndReached = dimension.getOnEndReachedHelper().perform({ | ||
...scrollMetrics, | ||
contentLength: dimension.getContainerOffset() + total, | ||
}).isEndReached; | ||
} | ||
} | ||
if (isEndReached) { | ||
@@ -21,0 +38,0 @@ return { |
@@ -73,6 +73,2 @@ import Dimension from '../../Dimension'; | ||
ctx.visibleIndexRange.endIndex = maxVisibleEndIndex; | ||
// ctx.visibleIndexRange.endIndex = state?.visibleEndIndex | ||
// ? Math.min(state.visibleEndIndex, maxVisibleEndIndex) | ||
// : maxVisibleEndIndex; | ||
}; |
@@ -19,2 +19,17 @@ import preCheck from './middleware/preCheck'; | ||
resolveIndexRange(state, payload, ctx); | ||
const { dimension } = payload; | ||
// if visibleStartIndex and visibleEndIndex not change, then return directly | ||
if ( | ||
state.visibleEndIndex === ctx.visibleIndexRange.endIndex && | ||
state.visibleStartIndex === ctx.visibleIndexRange.startIndex && | ||
!dimension.hasUnLayoutItems() | ||
) { | ||
if (state.actionType === 'hydrationWithBatchUpdate') return state; | ||
return { | ||
...state, | ||
actionType: 'hydrationWithBatchUpdate', | ||
}; | ||
} | ||
hydrateOnEndReached(state, payload, ctx); | ||
@@ -57,2 +72,13 @@ resolveMaxIndex(state, payload, ctx); | ||
resolveIndexRange(state, payload, ctx); | ||
if ( | ||
state.visibleEndIndex === ctx.visibleIndexRange.endIndex && | ||
state.visibleStartIndex === ctx.visibleIndexRange.startIndex | ||
) { | ||
if (state.actionType === 'recalculate') return state; | ||
return { | ||
...state, | ||
actionType: 'recalculate', | ||
}; | ||
} | ||
hydrateOnEndReached(state, payload, ctx); | ||
@@ -94,2 +120,15 @@ resolveMaxIndex(state, payload, ctx); | ||
resolveIndexRange(state, payload, ctx); | ||
if ( | ||
state.visibleEndIndex === ctx.visibleIndexRange.endIndex && | ||
state.visibleStartIndex === ctx.visibleIndexRange.startIndex | ||
) { | ||
if (state.actionType === 'scrollDown') return state; | ||
return { | ||
...state, | ||
actionType: 'scrollDown', | ||
}; | ||
} | ||
hydrateOnEndReached(state, payload, ctx); | ||
@@ -131,2 +170,15 @@ resolveMaxIndex(state, payload, ctx); | ||
resolveIndexRange(state, payload, ctx); | ||
if ( | ||
state.visibleEndIndex === ctx.visibleIndexRange.endIndex && | ||
state.visibleStartIndex === ctx.visibleIndexRange.startIndex | ||
) { | ||
if (state.actionType === 'scrollUp') return state; | ||
return { | ||
...state, | ||
actionType: 'scrollUp', | ||
}; | ||
} | ||
hydrateOnEndReached(state, payload, ctx); | ||
@@ -133,0 +185,0 @@ resolveMaxIndex(state, payload, ctx); |
@@ -52,3 +52,9 @@ import Batchinator from '@x-oasis/batchinator'; | ||
perform(scrollMetrics: ScrollMetrics) { | ||
/** | ||
* | ||
* @param scrollMetrics | ||
* @param positive | ||
* @returns | ||
*/ | ||
perform(scrollMetrics: ScrollMetrics, positive = false) { | ||
const { contentLength, offset, visibleLength } = scrollMetrics; | ||
@@ -58,2 +64,9 @@ const distanceFromEnd = contentLength - visibleLength - offset; | ||
if (positive && distanceFromEnd < 0) { | ||
return { | ||
distanceFromEnd, | ||
isEndReached: false, | ||
}; | ||
} | ||
return { | ||
@@ -60,0 +73,0 @@ distanceFromEnd, |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
1613677
19488