@@ -46,6 +46,20 @@ export abstract class LiveCollection<T, V> {
4646 }
4747}
4848
49+ function valuesMatching < V > (
50+ liveIdx : number , liveValue : V , newIdx : number , newValue : V ,
51+ trackBy : TrackByFunction < V > ) : number {
52+ if ( liveIdx === newIdx && Object . is ( liveValue , newValue ) ) {
53+ // matching and no value identity to update
54+ return 1 ;
55+ } else if ( Object . is ( trackBy ( liveIdx , liveValue ) , trackBy ( newIdx , newValue ) ) ) {
56+ // matching but requires value identity update
57+ return - 1 ;
58+ }
59+
60+ return 0 ;
61+ }
62+
4963/**
5064 * The live collection reconciliation algorithm that perform various in-place operations, so it
5165 * reflects the content of the new (incoming) collection.
@@ -84,34 +98,42 @@ export function reconcile<T, V>(
8498 while ( liveStartIdx <= liveEndIdx && liveStartIdx <= newEndIdx ) {
8599 // compare from the beginning
86100 const liveStartValue = liveCollection . at ( liveStartIdx ) ;
87- const liveStartKey = trackByFn ( liveStartIdx , liveStartValue ) ;
88101 const newStartValue = newCollection [ liveStartIdx ] ;
89- const newStartKey = trackByFn ( liveStartIdx , newStartValue ) ;
90- if ( Object . is ( liveStartKey , newStartKey ) ) {
91- liveCollection . updateValue ( liveStartIdx , newStartValue ) ;
102+ const isStartMatching =
103+ valuesMatching ( liveStartIdx , liveStartValue , liveStartIdx , newStartValue , trackByFn ) ;
104+ if ( isStartMatching !== 0 ) {
105+ if ( isStartMatching < 0 ) {
106+ liveCollection . updateValue ( liveStartIdx , newStartValue ) ;
107+ }
92108 liveStartIdx ++ ;
93109 continue ;
94110 }
95111
96112 // compare from the end
97113 // TODO(perf): do _all_ the matching from the end
98114 const liveEndValue = liveCollection . at ( liveEndIdx ) ;
99- const liveEndKey = trackByFn ( liveEndIdx , liveEndValue ) ;
100- const newEndItem = newCollection [ newEndIdx ] ;
101- const newEndKey = trackByFn ( newEndIdx , newEndItem ) ;
102- if ( Object . is ( liveEndKey , newEndKey ) ) {
103- liveCollection . updateValue ( liveEndIdx , newEndItem ) ;
115+ const newEndValue = newCollection [ newEndIdx ] ;
116+ const isEndMatching =
117+ valuesMatching ( liveEndIdx , liveEndValue , newEndIdx , newEndValue , trackByFn ) ;
118+ if ( isEndMatching !== 0 ) {
119+ if ( isEndMatching < 0 ) {
120+ liveCollection . updateValue ( liveEndIdx , newEndValue ) ;
121+ }
104122 liveEndIdx -- ;
105123 newEndIdx -- ;
106124 continue ;
107125 }
108126
109127 // Detect swap / moves:
128+ const liveStartKey = trackByFn ( liveStartIdx , liveStartValue ) ;
129+ const liveEndKey = trackByFn ( liveEndIdx , liveEndValue ) ;
130+ const newStartKey = trackByFn ( liveStartIdx , newStartValue ) ;
131+ const newEndKey = trackByFn ( newEndIdx , newEndValue ) ;
110132 if ( Object . is ( newStartKey , liveEndKey ) && Object . is ( newEndKey , liveStartKey ) ) {
111133 // swap on both ends;
112134 liveCollection . swap ( liveStartIdx , liveEndIdx ) ;
113135 liveCollection . updateValue ( liveStartIdx , newStartValue ) ;
114- liveCollection . updateValue ( liveEndIdx , newEndItem ) ;
136+ liveCollection . updateValue ( liveEndIdx , newEndValue ) ;
115137 newEndIdx -- ;
116138 liveStartIdx ++ ;
117139 liveEndIdx -- ;
@@ -164,13 +186,17 @@ export function reconcile<T, V>(
164186 const newCollectionIterator = newCollection [ Symbol . iterator ] ( ) ;
165187 let newIterationResult = newCollectionIterator . next ( ) ;
166188 while ( ! newIterationResult . done && liveStartIdx <= liveEndIdx ) {
189+ const liveValue = liveCollection . at ( liveStartIdx ) ;
167190 const newValue = newIterationResult . value ;
168191 const newKey = trackByFn ( liveStartIdx , newValue ) ;
169- const liveValue = liveCollection . at ( liveStartIdx ) ;
170192 const liveKey = trackByFn ( liveStartIdx , liveValue ) ;
171- if ( Object . is ( liveKey , newKey ) ) {
172- // found a match - move on
173- liveCollection . updateValue ( liveStartIdx , newValue ) ;
193+ const isStartMatching =
194+ valuesMatching ( liveStartIdx , liveValue , liveStartIdx , newValue , trackByFn ) ;
195+ if ( isStartMatching !== 0 ) {
196+ // found a match - move on, but update value
197+ if ( isStartMatching < 0 ) {
198+ liveCollection . updateValue ( liveStartIdx , newValue ) ;
199+ }
174200 liveStartIdx ++ ;
175201 newIterationResult = newCollectionIterator . next ( ) ;
176202 } else {
0 commit comments