Skip to content

Commit

Permalink
feat: add useItemApproximateLength support close #34
Browse files Browse the repository at this point in the history
  • Loading branch information
ryuever committed Jun 27, 2023
1 parent 1174924 commit 64ea822
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 13 deletions.
10 changes: 10 additions & 0 deletions packages/data-model/src/ItemMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ItemMeta extends ViewabilityItemMeta {
readonly getMetaOnViewableItemsChanged?: any;
readonly _ownerId: string;
readonly _canIUseRIC?: boolean;
private _isApproximateLayout: boolean;

constructor(props: {
onViewable?: StateEventListener;
Expand Down Expand Up @@ -60,6 +61,7 @@ class ItemMeta extends ViewabilityItemMeta {
: {};

this._canIUseRIC = canIUseRIC;
this._isApproximateLayout = false;

// this.addStateListener = this.addStateListener.bind(this);
// this.removeStateListener = this.removeStateListener.bind(this);
Expand All @@ -70,6 +72,14 @@ class ItemMeta extends ViewabilityItemMeta {
return this._id;
}

get isApproximateLayout() {
return this._isApproximateLayout;
}

set isApproximateLayout(value: boolean) {
this._isApproximateLayout = value;
}

setLayout(layout: ItemLayout) {
this._layout = layout;
}
Expand Down
52 changes: 41 additions & 11 deletions packages/data-model/src/ListDimensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
shallowDiffers,
buildStateTokenIndexKey,
DISPATCH_METRICS_THRESHOLD,
DEFAULT_ITEM_APPROXIMATE_LENGTH,
} from './common';
import resolveChanged from '@x-oasis/resolve-changed';
import manager from './manager';
Expand Down Expand Up @@ -48,6 +49,7 @@ import memoizeOne from 'memoize-one';
import shallowEqual from '@x-oasis/shallow-equal';
import shallowArrayEqual from '@x-oasis/shallow-array-equal';
import StillnessHelper from './utils/StillnessHelper';
import defaultBooleanValue from '@x-oasis/default-boolean-value';

class ListDimensions<ItemT extends {} = {}> extends BaseDimensions {
private _data: Array<ItemT> = [];
Expand Down Expand Up @@ -113,13 +115,17 @@ class ListDimensions<ItemT extends {} = {}> extends BaseDimensions {
state: ListState<ItemT>
) => RecycleStateResult<ItemT>;

private _itemApproximateLength: number;
private _approximateMode: boolean;

constructor(props: ListDimensionsProps<ItemT>) {
super({
...props,
isIntervalTreeItems: true,
});
const {
store,
recycleEnabled,
data = [],
deps = [],
keyExtractor,
Expand All @@ -134,24 +140,29 @@ class ListDimensions<ItemT extends {} = {}> extends BaseDimensions {
persistanceIndices,
dispatchMetricsThreshold = DISPATCH_METRICS_THRESHOLD,

itemApproximateLength,
useItemApproximateLength,
itemApproximateLength = DEFAULT_ITEM_APPROXIMATE_LENGTH,

stillnessThreshold,
onEndReachedTimeoutThreshold,
distanceFromEndThresholdValue,
onEndReachedHandlerTimeoutThreshold,

maxCountOfHandleOnEndReachedAfterStillness,
} = props;
// this.approximateLayoutGetter = this.approximateLayoutGetter.bind(this)

this._keyExtractor = keyExtractor;
this._getItemLayout =
getItemLayout ||
(itemApproximateLength
? (_, index) => ({
length: itemApproximateLength,
index,
})
: null);
this._itemApproximateLength = itemApproximateLength || 0;
this._getItemLayout = getItemLayout;

// `_approximateMode` is enabled on default
this._approximateMode = recycleEnabled
? defaultBooleanValue(
useItemApproximateLength,
typeof this._getItemLayout !== 'function' ||
!this._itemApproximateLength
)
: false;
this._getItemSeparatorLength = getItemSeparatorLength;
// for ListItem include a basic items condition
this._parentItemsDimensions = parentItemsDimensions;
Expand Down Expand Up @@ -473,6 +484,12 @@ class ListDimensions<ItemT extends {} = {}> extends BaseDimensions {
const oldLength = this.intervalTree.getHeap()[1];
this.intervalTree.set(index, length);
const nextLength = this.intervalTree.getHeap()[1];
const len = this.intervalTree.getMaxUsefulLength();

if (typeof nextLength === 'number')
this._itemApproximateLength = this.normalizeLengthNumber(
nextLength / Math.max(len, 1)
);

if (oldLength !== nextLength && this._listGroupDimension) {
this._listGroupDimension.recalculateDimensionsIntervalTreeBatchinator.schedule();
Expand Down Expand Up @@ -521,6 +538,17 @@ class ListDimensions<ItemT extends {} = {}> extends BaseDimensions {
canIUseRIC: this.canIUseRIC,
});

if (this._approximateMode) {
meta.setLayout({ x: 0, y: 0, height: 0, width: 0 });
this._selectValue.setLength(
meta.getLayout(),
this._itemApproximateLength
);
meta.isApproximateLayout = true;

return meta;
}

if (typeof this._getItemLayout === 'function') {
const { length } = this._getItemLayout(data, index);
// only List with getItemLayout has default layout value
Expand Down Expand Up @@ -884,6 +912,7 @@ class ListDimensions<ItemT extends {} = {}> extends BaseDimensions {
let length = this.normalizeLengthNumber(info);
if (this._selectValue.selectLength(meta.getLayout() || {}) !== length) {
this._selectValue.setLength(meta.ensureLayout(), length);
meta.isApproximateLayout = false;

if (index !== this._data.length - 1) {
length = meta.getSeparatorLength() + length;
Expand Down Expand Up @@ -918,6 +947,7 @@ class ListDimensions<ItemT extends {} = {}> extends BaseDimensions {
);
let length = this._selectValue.selectLength((_info as ItemLayout) || {});
meta.setLayout(_info as ItemLayout);
meta.isApproximateLayout = false;
// 只有关心的值发生变化时,才会再次触发setIntervalTreeValue
if (currentLength !== length && _update) {
if (index !== this._data.length - 1) {
Expand Down Expand Up @@ -1228,7 +1258,7 @@ class ListDimensions<ItemT extends {} = {}> extends BaseDimensions {
// remainingPosition
// );

if (this._getItemLayout) {
if (this._getItemLayout || this._approximateMode) {
if (Math.abs(velocity) <= 1) {
this.updateIndices(targetIndices, {
safeRange,
Expand Down
5 changes: 3 additions & 2 deletions packages/data-model/src/__test__/ListDimensions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,7 @@ describe('setData', () => {
width: 375,
height: 2000,
}),
useItemApproximateLength: false,
});

let _intervalTree = recycleList.intervalTree;
Expand Down Expand Up @@ -1891,8 +1892,8 @@ describe('data update', () => {

recycleListStateResult = recycleList.stateResult as RecycleStateResult<any>;

// offset should be recalculate
expect(recycleListStateResult.recycleState[0].offset).toBe(280);
// offset should be recalculate, approximateItemLength will be included.
expect(recycleListStateResult.recycleState[0].offset).toBe(370.5);
// the third as first item in recycleState
expect(recycleListStateResult.recycleState[0].targetKey).toBe('3');
});
Expand Down
1 change: 1 addition & 0 deletions packages/data-model/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const ON_END_REACHED_HANDLER_TIMEOUT_THRESHOLD = 2000;
export const DISPATCH_METRICS_THRESHOLD = 50;
export const RECYCLE_BUFFERED_COUNT = 4;
export const LENGTH_PRECISION = 4;
export const DEFAULT_ITEM_APPROXIMATE_LENGTH = 80;

// 建议 ON_END_REACHED_THRESHOLD * VisibleLength > MAX_TO_RENDER_PER_BATCH * itemLength
// 这样可以在滚动停止的时候,自动获取一屏幕
Expand Down
1 change: 1 addition & 0 deletions packages/data-model/src/types/Dimensions.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export type ListDimensionsProps<ItemT> = {
canIUseRIC?: boolean;

itemApproximateLength?: number;
useItemApproximateLength?: boolean;
} & BaseDimensionsProps &
OnEndReachedHelperProps;

Expand Down

0 comments on commit 64ea822

Please sign in to comment.