TIL: concatLatestFrom does not wait

Search for a command to run...

No comments yet. Be the first to comment.
Today I learned how to move a branch that was incorrectly based on another branch to a different starting point. This was useful when I wanted to merge a feature branch sooner but realized it was branched off the wrong base. The Scenario Branch A is...

What is the tap operator? I recently learned about the tap operator when trying to perform a side-effect inside of a map operator. While you could perform side-effects inside of a map operator, it's a better practice to do so in a tap operator where...

As someone new to RxJS, I found the Operator Decision Tree page incredibly helpful. This page provides a visual guide that simplifies the process of choosing the right RxJS operator by presenting a series of questions that lead you to the optimal cho...

An API Client Alternative

Today, I learned that concatLatestFrom in NgRx does not wait for an observable to emit a valid value before proceeding. Instead, it simply grabs the latest available value at the time an action is dispatched. If the observable has not emitted yet, your effect might not behave as expected.
Consider this effect where we try to retrieve a value from the store when actionA is dispatched:
myEffect$ = createEffect(() =>
this.actions$.pipe(
ofType(MyActions.actionA),
concatLatestFrom(() =>
this.store.select(selectCondition).pipe(
filter(value => value === true) // Only emits when true
)
),
map(([action, condition]) => MyActions.nextAction({ condition }))
)
);
What happens here?
If actionA is dispatched before selectCondition emits true, the effect does not wait—it just won’t run or may break.
concatLatestFrom doesn’t re-trigger when selectCondition eventually becomes true.
switchMap + combineLatestIf you need to wait until a condition is met, use switchMap and combineLatest instead:
myEffect$ = createEffect(() =>
this.actions$.pipe(
ofType(MyActions.actionA),
switchMap(() =>
this.store.select(selectCondition).pipe(
filter(value => value === true), // Waits until true
map(value => MyActions.nextAction({ condition: value }))
)
)
)
);
switchMap starts a new observable each time actionA is dispatched.
filter(value => value === true) ensures we wait until the condition is met before proceeding.
Once selectCondition emits true, nextAction is dispatched.
If you need to wait for two conditions to become true, use combineLatest with filter:
myEffect$ = createEffect(() =>
this.actions$.pipe(
ofType(MyActions.actionA),
switchMap(() =>
combineLatest([
this.store.select(selectConditionOne),
this.store.select(selectConditionTwo)
]).pipe(
filter(([cond1, cond2]) => cond1 === true && cond2 === true),
map(([cond1, cond2]) => MyActions.nextAction({ cond1, cond2 }))
)
)
)
);
This ensures that the effect only runs when both conditions are true.
Use concatLatestFrom when you just need the latest value at action dispatch.
❌ Don’t use concatLatestFromif you need to wait for a condition to become true.
✅ Use switchMap + filter (or combineLatest) to wait for conditions.