@@ -136,41 +136,46 @@ class List<T> extends React.Component<ListProps<T>, ListState> {
136
136
this . setState ( { status : 'MEASURE_DONE' , startItemTop } ) ;
137
137
}
138
138
139
+ // TODO: If is add node
139
140
// Re-calculate the scroll position align with the current visible item position
140
141
if ( prevProps . dataSource . length !== dataSource . length && height ) {
141
- // We will record all the visible item top for next loop match check
142
- const originItemTops : OriginValues = [ ] ;
142
+ /**
143
+ * When an item removed,
144
+ * we should know the item (called as compare item) before the removed item position.
145
+ * After loop re-calculation, we need keep the compare item position not change.
146
+ */
147
+ // Find removed item key
148
+ const removedItemIndex : number = prevProps . dataSource . findIndex ( ( _ , index ) => {
149
+ const key = this . getItemKey ( index , prevProps ) ;
150
+ return dataSource . every ( ( __ , nextIndex ) => key !== this . getItemKey ( nextIndex ) ) ;
151
+ } ) ;
152
+
153
+ // We use the item before removed item as base compare position to enhance the accuracy
154
+ const compareItemIndex = removedItemIndex - 1 ;
155
+ const compareItemKey = this . getItemKey ( compareItemIndex , prevProps ) ;
156
+
143
157
const { startIndex : originStartIndex , itemIndex : originItemIndex } = this . state ;
144
- let originStartItemTop = this . state . startItemTop ;
158
+ let compareItemTop = this . state . startItemTop ;
145
159
for ( let index = originStartIndex ; index <= originItemIndex ; index += 1 ) {
146
160
const key = this . getItemKey ( index , prevProps ) ;
147
- originItemTops . push ( {
148
- key,
149
- top : originStartItemTop ,
150
- } ) ;
151
- originStartItemTop += this . itemElementHeights [ key ] || 0 ;
152
- }
161
+ if ( key === compareItemKey ) {
162
+ break ;
163
+ }
153
164
154
- console . log (
155
- 'Length changed. Origin top:' ,
156
- originItemTops ,
157
- this . state . startIndex ,
158
- this . itemElementHeights ,
159
- ) ;
165
+ compareItemTop += this . itemElementHeights [ key ] || 0 ;
166
+ }
160
167
161
- // Loop to get the adjusted item top
168
+ // Loop to generate compared item top and find best one
162
169
const { scrollHeight, clientHeight } = this . listRef . current ;
163
170
const maxScrollTop = scrollHeight - clientHeight ;
164
171
165
- let bestScrollTop : number | null = null ;
166
- let bestSimilarity = Number . MAX_VALUE ;
172
+ let bestScrollTop : number = null ;
173
+ let bestSimilarity : number = Number . MAX_VALUE ;
167
174
let bestItemIndex = 0 ;
168
175
let bestItemOffsetPtg = 0 ;
169
176
let bestStartIndex = 0 ;
170
177
let bestEndIndex = 0 ;
171
178
172
- let debugItemTops : TargetValues = null ;
173
-
174
179
for ( let scrollTop = 0 ; scrollTop < maxScrollTop ; scrollTop += 1 ) {
175
180
const scrollPtg = getScrollPercentage ( { scrollTop, scrollHeight, clientHeight } ) ;
176
181
const visibleCount = Math . ceil ( height / itemHeight ) ;
@@ -191,34 +196,38 @@ class List<T> extends React.Component<ListProps<T>, ListState> {
191
196
getItemKey : this . getItemKey ,
192
197
} ) ;
193
198
194
- const itemTops : TargetValues = { } ;
195
- for ( let index = itemIndex ; index > startIndex ; index -= 1 ) {
199
+ let newCompareItemTop : number = null ;
200
+ for ( let index = itemIndex ; index >= startIndex ; index -= 1 ) {
196
201
const key = this . getItemKey ( index ) ;
197
- itemTops [ key ] = locatedItemTop ;
202
+ if ( key === compareItemKey ) {
203
+ newCompareItemTop = locatedItemTop ;
204
+ break ;
205
+ }
206
+
207
+ if ( index <= 0 ) {
208
+ break ;
209
+ }
210
+
198
211
const prevItemKey = this . getItemKey ( index - 1 ) ;
199
212
locatedItemTop -= this . itemElementHeights [ prevItemKey ] || 0 ;
200
213
}
201
214
202
- const similarity = getSimilarity ( originItemTops , itemTops ) ;
203
- const absSimilarity = Math . abs ( similarity ) ;
204
-
205
- if ( absSimilarity < bestSimilarity ) {
206
- bestSimilarity = absSimilarity ;
207
- bestScrollTop = scrollTop ;
208
- bestItemIndex = itemIndex ;
209
- bestItemOffsetPtg = itemOffsetPtg ;
210
- bestStartIndex = startIndex ;
211
- bestEndIndex = endIndex ;
212
-
213
- debugItemTops = itemTops ;
215
+ if ( newCompareItemTop !== null ) {
216
+ const similarity = Math . abs ( newCompareItemTop - compareItemTop ) ;
217
+ if ( similarity < bestSimilarity ) {
218
+ bestScrollTop = scrollTop ;
219
+ bestSimilarity = similarity ;
220
+ bestItemIndex = itemIndex ;
221
+ bestItemOffsetPtg = itemOffsetPtg ;
222
+ bestStartIndex = startIndex ;
223
+ bestEndIndex = endIndex ;
224
+ }
214
225
}
215
-
216
- console . log ( 'COMPARE:' , absSimilarity . toFixed ( 3 ) , itemTops ) ;
217
226
}
218
227
219
- if ( bestScrollTop ) {
220
- console . log ( 'Best Top :' , bestScrollTop , bestSimilarity , debugItemTops ) ;
221
- console . log ( 'StartIndex:' , bestStartIndex , this . getItemKey ( bestStartIndex ) ) ;
228
+ // Update `scrollTop` to new calculated position
229
+ console . log ( 'DONE :' , bestScrollTop ) ;
230
+ if ( bestScrollTop !== null ) {
222
231
this . lockScroll = true ;
223
232
this . listRef . current . scrollTop = bestScrollTop ;
224
233
0 commit comments