Skip to content

Commit 13a64fb

Browse files
committed
find best match
1 parent 7a16d1e commit 13a64fb

File tree

3 files changed

+49
-8
lines changed

3 files changed

+49
-8
lines changed

examples/animate.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function genItem() {
1616
}
1717

1818
const originDataSource: Item[] = [];
19-
for (let i = 0; i < 20; i += 1) {
19+
for (let i = 0; i < 10; i += 1) {
2020
originDataSource.push(genItem());
2121
}
2222

src/List.tsx

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import {
77
getRangeIndex,
88
getItemTop,
99
GHOST_ITEM_KEY,
10+
OriginValues,
11+
TargetValues,
12+
getSimilarity,
1013
} from './util';
1114

1215
type RenderFunc<T> = (item: T) => React.ReactNode;
@@ -128,12 +131,15 @@ class List<T> extends React.Component<ListProps<T>, ListState> {
128131
// Re-calculate the scroll position align with the current visible item position
129132
if (prevProps.dataSource.length !== dataSource.length && height) {
130133
// We will record all the visible item top for next loop match check
131-
const originItemTops: { [key: string]: number } = {};
134+
const originItemTops: OriginValues = [];
132135
const { startIndex: originStartIndex, itemIndex: originItemIndex } = this.state;
133136
let originStartItemTop = this.state.startItemTop;
134137
for (let index = originStartIndex; index <= originItemIndex; index += 1) {
135138
const key = this.getItemKey(index, prevProps);
136-
originItemTops[key] = originStartItemTop;
139+
originItemTops.push({
140+
key,
141+
top: originStartItemTop,
142+
});
137143
originStartItemTop += this.itemElementHeights[key] || 0;
138144
}
139145

@@ -147,7 +153,12 @@ class List<T> extends React.Component<ListProps<T>, ListState> {
147153
// Loop to get the adjusted item top
148154
const { scrollHeight, clientHeight } = this.listRef.current;
149155
const maxScrollTop = scrollHeight - clientHeight;
150-
for (let scrollTop = 0; scrollTop <= maxScrollTop; scrollTop += 1) {
156+
157+
let bestScrollTop: number | null = null;
158+
let bestSimilarity = Number.MAX_VALUE;
159+
let debugItemTops: TargetValues = null;
160+
161+
for (let scrollTop = 0; scrollTop < maxScrollTop; scrollTop += 1) {
151162
const scrollPtg = getScrollPercentage({ scrollTop, scrollHeight, clientHeight });
152163
const visibleCount = Math.ceil(height / itemHeight);
153164

@@ -167,14 +178,27 @@ class List<T> extends React.Component<ListProps<T>, ListState> {
167178
getItemKey: this.getItemKey,
168179
});
169180

170-
const itemTops: { [key: string]: number } = {};
171-
for (let index = itemIndex; index >= startIndex; index -= 1) {
181+
const itemTops: TargetValues = {};
182+
for (let index = itemIndex; index > startIndex; index -= 1) {
172183
const key = this.getItemKey(index);
173184
itemTops[key] = locatedItemTop;
174-
locatedItemTop -= this.itemElementHeights[key] || 0;
185+
const prevItemKey = this.getItemKey(index - 1);
186+
locatedItemTop -= this.itemElementHeights[prevItemKey] || 0;
175187
}
176188

177-
console.log('=>', scrollTop, itemTops);
189+
const similarity = getSimilarity(originItemTops, itemTops);
190+
if (similarity < bestSimilarity) {
191+
bestSimilarity = similarity;
192+
bestScrollTop = scrollTop;
193+
debugItemTops = itemTops;
194+
}
195+
196+
console.log('=>', scrollTop, itemTops, getSimilarity(originItemTops, itemTops));
197+
}
198+
199+
if (bestScrollTop) {
200+
console.log('Best Top:', bestScrollTop, debugItemTops);
201+
this.listRef.current.scrollTop = bestScrollTop;
178202
}
179203
}
180204
}

src/util.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,20 @@ export function getItemTop({
118118

119119
return locatedItemMergedTop;
120120
}
121+
122+
export type OriginValues = {
123+
key: string;
124+
top: number;
125+
}[];
126+
export interface TargetValues {
127+
[key: string]: number;
128+
}
129+
export function getSimilarity(origin: OriginValues, target: TargetValues): number {
130+
for (let index = 0; index < origin.length; index += 1) {
131+
const { key, top } = origin[index];
132+
if (key in target) {
133+
return Math.abs(target[key] - top);
134+
}
135+
}
136+
return Number.MAX_VALUE;
137+
}

0 commit comments

Comments
 (0)