177
*/
178
export function autorunPerKeyedItem<TIn, TKey>(
179
>
items: IObservable<readonly TIn[]>,
autorun.ts
180
>
keyFn: (input: TIn) => TKey,
181
>
setup: (key: TKey, value: IObservable<TIn>, store: DisposableStore) => void,
182
>
debugLocation = DebugLocation.ofCaller()
183
>
): IDisposable {
184
>
interface ICell {
185
>
readonly value: ISettableObservable<TIn>;
186
>
readonly store: DisposableStore;
187
>
}
188
>
const cells = new Map<TKey, ICell>();
189
>
const ar = autorunOpts({ debugReferenceFn: setup }, reader => {
190
>
const arr = items.read(reader);
191
>
const seen = new Set<TKey>();
192
>
const additions: { key: TKey; cell: ICell }[] = [];
193
>
transaction(tx => {
194
>
for (const item of arr) {
195
>
const key = keyFn(item);
196
>
seen.add(key);
197
>
const existing = cells.get(key);
198
>
if (existing) {
199
>
existing.value.set(item, tx);
200
>
} else {
201
>
const store = new DisposableStore();
202
>
const value = observableValue<TIn>('keyedItem', item);
203
>
const cell: ICell = { value, store };
204
>
cells.set(key, cell);
205
>
additions.push({ key, cell });
206
>
}
207
>
}
208
>
for (const [k, cell] of cells) {
209
>
if (!seen.has(k)) {
210
cell.store.dispose();
211
cells.delete(k);
212
}
214
>
});
215
>
// Setup runs after the transaction so per-key autoruns observe the
216
>
// final cell values on their first read.
217
>
for (const { key, cell } of additions) {
218
>
setup(key, cell.value, cell.store);
219
>
}
220
>
}, debugLocation);
221
>
return toDisposable(() => {
222
>
ar.dispose();
223
>
for (const cell of cells.values()) {
224
>
cell.store.dispose();
225
>
}
226
>
cells.clear();
227
>
});
228
>
}
229
230
export interface IReaderWithDispose extends IReaderWithStore, IDisposable { }