I have an array of Observables streams$ which each emit a value once, when the associated async operation completes. I want to aggregate the results in an array arr, where arr[i] = undefined if streams$[i] hasn't completed, and the resolved value of streams$[i] if it has, so for 3 observables, the hook should return the following:
[undefined, undefined, undefined] // 1
['A', undefined, undefined] // 2
['A', undefined, 'C'] // 3
['A', 'B', 'C'] // 4
// done, unsubscribe
This is what I have currently:
const useLatest = <T>(streams$: Observables<T>[]) => {
const [state, setState] = useState<T[]>(Array(streams$.length).fill(undefined));
const latest$ = combineLatest(streams$.map($ => $.pipe(startWith(undefined))));
useEffect(() => {
const subscription = latest$.subscribe((values) => setState(values));
return () => {
subscription.unsubscribe();
}
}, []);
return state;
}
This gives me close to the correct return values (prints all undefined twice), but due to the empty dependency array will not recompute if streams$ becomes a different array of new observables. Other things I've done to try and fix this either result in infinite emissions of either [undefined, undefined, undefined] or ['A', 'B', 'C']. Using things like piping latest$ to takeWhile with second parameter true, or piping the individual streams$[i] to take(2), etc.