Skip to content

Commit

Permalink
Merge pull request #215 from spierala/signal-store-imperative-state-read
Browse files Browse the repository at this point in the history
feat(signal-store): imperative state read returns raw state
  • Loading branch information
spierala authored Apr 18, 2024
2 parents fcfa9b2 + 67af68d commit 13114de
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 20 deletions.
17 changes: 6 additions & 11 deletions libs/signal-store/src/lib/component-store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DestroyRef, inject, Signal, signal, WritableSignal } from '@angular/core';
import { DestroyRef, inject, signal, WritableSignal } from '@angular/core';
import {
Action,
calculateExtensions,
Expand Down Expand Up @@ -34,14 +34,9 @@ export class ComponentStore<StateType extends object> implements ComponentStoreL
private actionsOnQueue = createActionsOnQueue();

private _state: WritableSignal<StateType> = signal(this.initialState);
private selectableState = createSelectableSignalState(this._state);

/**
* @deprecated
* Use the `select` method without arguments to return a state Signal
* the `state` property will be replaced with a getter function which returns the raw state (like in the original MiniRx Store)
*/
state: Signal<StateType> = this.selectableState.select();
get state(): StateType {
return this._state();
}

private updateState: UpdateStateCallback<StateType> = (
stateOrCallback: StateOrCallback<StateType>,
Expand Down Expand Up @@ -69,7 +64,7 @@ export class ComponentStore<StateType extends object> implements ComponentStoreL

const subSink = createSignalStoreSubSink();
subSink.sink = this.actionsOnQueue.actions$.subscribe((action) => {
const newState: StateType = reducer(this.state(), action);
const newState: StateType = reducer(this.state, action);
this._state.set(newState);
});

Expand All @@ -87,7 +82,7 @@ export class ComponentStore<StateType extends object> implements ComponentStoreL
setState = createUpdateFn(this.updateState);
connect = createConnectFn(this.updateState);
rxEffect = createRxEffectFn();
select = this.selectableState.select;
select = createSelectableSignalState(this._state).select;

private destroy(): void {
// Dispatch an action really just for logging via LoggerExtension
Expand Down
12 changes: 5 additions & 7 deletions libs/signal-store/src/lib/feature-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@ export class FeatureStore<StateType extends object> implements ComponentStoreLik
return this._featureKey;
}

/**
* @deprecated
* Use the `select` method without arguments to return a state Signal
* the `state` property will be replaced with a getter function which returns the raw state (like in the original MiniRx Store)
*/
state: Signal<StateType> = select((state) => state[this.featureKey]);
private _state: Signal<StateType> = select((state) => state[this.featureKey]);
get state(): StateType {
return this._state();
}

private updateState: UpdateStateCallback<StateType> = (
stateOrCallback: StateOrCallback<StateType>,
Expand Down Expand Up @@ -66,7 +64,7 @@ export class FeatureStore<StateType extends object> implements ComponentStoreLik
setState = createUpdateFn(this.updateState);
connect = createConnectFn(this.updateState);
rxEffect = createRxEffectFn();
select = createSelectableSignalState(this.state).select;
select = createSelectableSignalState(this._state).select;

private destroy(): void {
removeFeature(this._featureKey);
Expand Down
2 changes: 1 addition & 1 deletion libs/signal-store/src/lib/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Observable } from 'rxjs';
import { Action, StateOrCallback } from '@mini-rx/common';

export interface ComponentStoreLike<StateType> {
state: Signal<StateType>;
get state(): StateType;
setState(stateOrCallback: StateOrCallback<StateType>, name?: string): void;
connect(dict: Record<string, Observable<any> | Signal<any>>): void;
rxEffect(effectFn: (origin$: Observable<any>) => Observable<any>): () => void;
Expand Down
10 changes: 10 additions & 0 deletions libs/signal-store/src/lib/spec/component-store.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,4 +332,14 @@ describe('ComponentStore', () => {

expect(selectedState()).toBe(1);
});

it('should read state imperatively', () => {
const cs = setup({ counter: 0 });

expect(cs.state).toEqual({ counter: 0 });

cs.setState((state) => ({ counter: state.counter + 1 }));

expect(cs.state).toEqual({ counter: 1 });
});
});
12 changes: 11 additions & 1 deletion libs/signal-store/src/lib/spec/feature-store.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const getSomeFeatureSelector = createFeatureStateSelector<CounterState>('someFea
class UserFeatureStore extends FeatureStore<UserState> {
private injector = inject(EnvironmentInjector);

state$ = toObservable(this.state);
state$ = toObservable(this.select());
firstName = this.select((state) => state.firstName);
firstName$ = toObservable(this.firstName, { injector: this.injector });
lastName = this.select((state) => state.lastName);
Expand Down Expand Up @@ -562,4 +562,14 @@ describe('FeatureStore', () => {

expect(selectedState()).toBe(0);
});

it('should read state imperatively', () => {
setupCounterFeatureStore();

expect(counterFeatureStore.state).toEqual({ counter: 0 });

counterFeatureStore.increment();

expect(counterFeatureStore.state).toEqual({ counter: 1 });
});
});

0 comments on commit 13114de

Please sign in to comment.