Skip to content

Commit 8930e22

Browse files
feat(component-store): add ability for patchState to accept Observable (#2937)
Closes #2852
1 parent be69a63 commit 8930e22

File tree

2 files changed

+50
-11
lines changed

2 files changed

+50
-11
lines changed

modules/component-store/spec/component-store.spec.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
interval,
88
timer,
99
Observable,
10+
from,
1011
} from 'rxjs';
1112
import {
1213
delayWhen,
@@ -15,6 +16,8 @@ import {
1516
map,
1617
tap,
1718
finalize,
19+
delay,
20+
concatMap,
1821
} from 'rxjs/operators';
1922

2023
describe('Component Store', () => {
@@ -96,6 +99,19 @@ describe('Component Store', () => {
9699
);
97100
});
98101

102+
it('throws an Error when patchState with Observable is called before initialization', () => {
103+
const componentStore = new ComponentStore();
104+
105+
expect(() => {
106+
componentStore.patchState(of({ foo: 'bar' }));
107+
}).toThrow(
108+
new Error(
109+
'ComponentStore has not been initialized yet. ' +
110+
'Please make sure it is initialized before updating/getting.'
111+
)
112+
);
113+
});
114+
99115
it(
100116
'throws an Error when patchState with a function/callback is called' +
101117
' before initialization',
@@ -566,6 +582,28 @@ describe('Component Store', () => {
566582
})
567583
);
568584

585+
it(
586+
'with the values from Observable',
587+
marbles((m) => {
588+
componentStore.patchState(
589+
from([
590+
{ value1: 'foo' },
591+
{ value2: { foo: 'foo2' } },
592+
{ value1: 'baz' },
593+
]).pipe(concatMap((partialState) => of(partialState).pipe(delay(3))))
594+
);
595+
596+
m.expect(componentStore.state$).toBeObservable(
597+
m.hot('a--b--c--d', {
598+
a: INIT_STATE,
599+
b: { ...INIT_STATE, value1: 'foo' },
600+
c: { value1: 'foo', value2: { foo: 'foo2' } },
601+
d: { value1: 'baz', value2: { foo: 'foo2' } },
602+
})
603+
);
604+
})
605+
);
606+
569607
it(
570608
'with a value based on the previous state',
571609
marbles((m) => {

modules/component-store/src/component-store.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -174,19 +174,20 @@ export class ComponentStore<T extends object> implements OnDestroy {
174174
* @throws Error if the state is not initialized.
175175
*/
176176
patchState(
177-
partialStateOrUpdaterFn: Partial<T> | ((state: T) => Partial<T>)
177+
partialStateOrUpdaterFn:
178+
| Partial<T>
179+
| Observable<Partial<T>>
180+
| ((state: T) => Partial<T>)
178181
): void {
179-
this.setState((state) => {
180-
const patchedState =
181-
typeof partialStateOrUpdaterFn === 'function'
182-
? partialStateOrUpdaterFn(state)
183-
: partialStateOrUpdaterFn;
182+
const patchedState =
183+
typeof partialStateOrUpdaterFn === 'function'
184+
? partialStateOrUpdaterFn(this.get())
185+
: partialStateOrUpdaterFn;
184186

185-
return {
186-
...state,
187-
...patchedState,
188-
};
189-
});
187+
this.updater((state, partialState: Partial<T>) => ({
188+
...state,
189+
...partialState,
190+
}))(patchedState);
190191
}
191192

192193
protected get(): T;

0 commit comments

Comments
 (0)