Package Exports
- subjective
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (subjective) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Subjective
- Type safety state management
- Favors simple functions either for updating the state or as a state selector
- State as a class (optional, but recommended)
Concepts
- State
- const state = new Subjective(new MyState(), new MyStateFns())
- Selector function
- state.select(s => s.filter.a)
- Update function
- state.update(f => f.updateFilterA, item)
Usage
- Observable Service in Angular
- Observable Store
Examples
Observable Service in Angular
Service & State
Service is @Injectable and contains a reference to the state and async methods (for communication with backend). The state is instantiated as state property in Angular Service, but the whole state is defined together with update functions in xy.state.ts file.
- core
- stores
- cart
- cart.service.ts
- cart.state.ts
- product
- product.service.ts
- product.state.ts
- cart
- stores
Update state
Update state by using update functions inside update method of state instance. Payload type is inferred from the update function.
@Component({})
export class ProductDetailComponent {
constructor(private _productService: ProductService) {}
addLike(item: ProductItem) {
this._productService.state.update(f => f.addLike, item);
}
}
Update state & return Last updated state
Sometimes it's handy to have a snapshot of last updated state. Update method returns a snapshot of last updated state.
@Component({})
export class FilterTypeComponent {
@Output() search = new EventEmitter<Filter>();
constructor(private _productService: ProductService) {}
filter(type: FilterType) {
// update filter type & get last updated state
const lastUpdatedState = this._productService.state.update(
f => f.replaceFilterType,
type,
);
// search by filter
this.search.emit(lastUpdatedState.filter);
}
}
Subscribe to a state
Subscribe to a particular key of the state defined by selector function in select method and return value of the key.
@Component({
selector: 'app-list',
template: `
<ul>
<li *ngFor="let item of items | async">
{{item.name}}
</li>
</ul>
`,
})
export class ListComponent {
items = this._productService.state.select(s => s.items);
constructor(private _productService: ProductService) {}
}
Subscribe to a state & return whole state
Sometimes you need to react to changes of a particular key of the state and get the whole state. By using the second argument in the select method, you can get the whole state in subscribe callback.
@Component({
selector: 'app-list',
template: `
<ng-container *ngIf="state | async as state">
<ng-container *ngIf="state.isLoading; else items">
loading...
</ng-container>
<ng-template #items>
<h2>{{state.type}}</h2>
<ul>
<li *ngFor="let item of state.items">
{{item.name}}
</li>
</ul>
</ng-template>
</ng-container>
`,
})
export class ListComponent {
state = merge(
this._productService.state
.select(s => s.items, true),
this._productService.state
.select(s => s.isLoading, true);
)
constructor(private _productService: ProductService) {}
}
Snapshot
Get a snapshot of the last changed state. You can't be subscribed to it. Should be used rarely.
Initial State
Get the initial state of the state. It gets handy when you need to reset particular part of the state.
NOTES
Immutable pattern
Always use immutable pattern otherwise it will not work. We can't rely on mutations since object reference is always the same.
Type-safety
Types are always inferred either from state class or payload parameter of the update function.