{"id":24108291,"url":"https://github.com/reactgular/stateful","last_synced_at":"2025-02-28T03:21:55.712Z","repository":{"id":143784045,"uuid":"207930381","full_name":"reactgular/stateful","owner":"reactgular","description":"Stateful is a tiny state manager for TypeScript and RxJS projects.","archived":false,"fork":false,"pushed_at":"2020-07-18T06:29:18.000Z","size":214,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-04-25T11:43:02.091Z","etag":null,"topics":["javascript","library","redux","rxjs","state-management","tiny-library","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reactgular.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-12T00:24:37.000Z","updated_at":"2024-08-21T18:04:46.918Z","dependencies_parsed_at":"2023-06-08T16:15:22.518Z","dependency_job_id":null,"html_url":"https://github.com/reactgular/stateful","commit_stats":{"total_commits":6,"total_committers":3,"mean_commits":2.0,"dds":0.5,"last_synced_commit":"7304c36d4ef1c2140c84f6952c49b8a414223d4d"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactgular%2Fstateful","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactgular%2Fstateful/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactgular%2Fstateful/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactgular%2Fstateful/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reactgular","download_url":"https://codeload.github.com/reactgular/stateful/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241094271,"owners_count":19908647,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","library","redux","rxjs","state-management","tiny-library","typescript"],"created_at":"2025-01-10T23:35:37.734Z","updated_at":"2025-02-28T03:21:55.691Z","avatar_url":"https://github.com/reactgular.png","language":"TypeScript","readme":"[![Build Status](https://travis-ci.org/reactgular/stateful.svg?branch=master)](https://travis-ci.org/reactgular/stateful)\n[![Coverage Status](https://coveralls.io/repos/github/reactgular/stateful/badge.svg?branch=master)](https://coveralls.io/github/reactgular/stateful?branch=master)\n[![npm version](https://badge.fury.io/js/%40reactgular%2Fstateful.svg)](https://badge.fury.io/js/%40reactgular%2Fstateful)\n\n## What is Stateful?\n\nStateful is a tiny state manager for TypeScript and [RxJS](https://github.com/ReactiveX/RxJS) projects. It's a class that encapsulates a [BehaviorSubject](https://www.learnrxjs.io/subjects/behaviorsubject.html) and \nprovides basic store manipulation methods. It's indented for use in small classes that don't need the complexity of a larger state manager.\n\nStateful is about **1kb** in size after *minification*. \n\n## Installation\n\nTo get started, install the package from npm.\n\n```bash\nnpm install --save @reactgular/stateful\n```\n\n## Usage\n\nStateful is small, simple and easy to use.\n\n- You construct a Stateful object with a *default state* and use an interface to define the *state object* type.\n- You can then `patch()`, `set()` and `reset()` the internal state.\n- You use `select()` to create observables of state property changes, and `selector()` to create custom selectors.\n\n```typescript\nimport {Stateful} from '@reactgular/stateful';\n\ninterface ExampleState {name: string; count: number; }\nconst state = new Stateful\u003cExampleState\u003e({name: \"Example\", count: 4});\nstate.patch({name: 'Something'});\nstate.select('name').subscribe(value =\u003e console.log(value)); // prints \"Something\"\n```\n\n# Stateful Class\n\nUsage documentation for the `Stateful\u003cTState\u003e` class.\n\n#### Properties\n\n- `state$`: An observable that emits all changes to the state.\n\n#### Methods\n\n- `complete()`: Stops emitting changes made to the state.\n- `default()`: Returns the default state used with the constructor or reset.\n- `patch(state: Partial\u003cTState\u003e)`: Patches the current state with partial values.\n- `patch\u003cTKey extends keyof TState\u003e(name: TKey, value: TState[TKey])`: Patches a single property on the state with a value.\n- `reset(defaultState?: TState)`: Resets the state to the original state used by the constructor, or updates the original state with the passed argument.\n- `select\u003cTKey extends keyof TState\u003e(name: TKey): Observable\u003cTState[TKey]\u003e`: Creates an observable that emits values from a property on the state object.\n- `selector\u003cTValue\u003e(selector: (s: TState) =\u003e TValue): Observable\u003cTValue\u003e`: Creates an observable that emits values produced by the selector function. \n- `set(state: TState)`: Sets the current state.\n- `snapshot(): TState`: Peeks at the current internal state.\n\n## Examples\n\nYou can create *selectors* from the state by using property names. TypeScript will *infer* the correct `Observable\u003cType\u003e` from the property key.\n\n```typescript\nimport {Stateful} from '@reactgular/stateful';\n\ninterface ExampleState {name: string; count: number; }\nconst state = new Stateful\u003cExampleState\u003e({name: \"Example\", count: 4});\n\nconst name$ = state.select('name'); // Observable\u003cstring\u003e\nname$.subscribe(value =\u003e console.log(value)); // prints \"Example\", \"Hello World\"\n\nstate.patch({name: \"Hello World\"});\n```\n\nYou can write your own custom *selectors*.\n\n```typescript\nimport {Stateful} from '@reactgular/stateful';\n\ninterface ExampleState {name: string; count: number; }\nconst state = new Stateful\u003cExampleState\u003e({name: \"Example\", count: 4});\n\nconst nameAndCount$ = state.selector(state =\u003e `${state.name} AND ${state.count}`);\nnameAndCount$.subscribe(value =\u003e console.log(value)); // prints \"Example AND 4\"\n```\n\n## Example Angular Service\n\nYou can use Stateful as a base class for an Angular service.\n\n```typescript\nimport {Observable} from 'rxjs'; \nimport {Stateful} from '@reactgular/stateful';\n\ninterface ExampleState { counter: number }\n\n@Injectable()\nexport class ExampleService extends Stateful\u003cExampleState\u003e {\n    public constructor() {\n        super({counter: 0})\n    }\n \n    public counter(): Observable\u003cnumber\u003e {\n        return this.select('counter');\n    }\n\n    public increment() {\n        const counter = this.snapshot().counter + 1;\n        this.patch({counter});\n    }\n\n    public decrement() {\n        const counter = this.snapshot().counter - 1;\n        this.patch({counter});\n    }\n}\n```\n\n## Example Angular Component\n\nYou can use Stateful as an internal state manager for an Angular component. By patching incoming `@Input()` properties into the Stateful\nobject you can more easily work with observables.\n\n```typescript\ninterface ProductState {\n    productId?: number;\n    price?: number;\n}\n\n@Component({\n    selector: 'project',\n    template: `\u003cspan\u003ePrice: {{price$ | async}}\u003c/span\u003e\n               \u003cspan\u003eTaxes: {{taxes$ | async}}\u003c/span\u003e`\n})\nexport class ProductComponent implements OnInit {\n    private state: Stateful\u003cProductState\u003e = new Stateful\u003cProductState\u003e({});\n\n    public price$ = this.state.select('price');\n\n    public taxes$ = this.state.select('price').pipe(\n        map(price =\u003e price * 0.07)    \n    );\n\n    @Input()\n    public set productId(productId: string) {\n        this.state.patch({productId});    \n    }\n  \n    @Input()\n    public set price(price: string) {\n        this.state.patch({price});    \n    }\n}\n```\n\n# StorageStateful Class\n\nStorageStateful extends Stateful and offers persistence of state to a storage service like `localStorage` or `sessionStorage`.\n\n```typescript\nimport {StorageStateful} from '@reactgular/stateful';\n\ninterface ExampleState {name: string; count: number; }\nconst state = new StorageStateful\u003cExampleState\u003e('app', {name: \"Example\", count: 4});\n```\n\nPass the storage `key` as the first parameter to the constructor, and the default state as the second parameter. The state will\nbe persisted to `localStorage` by default under that `key`. Any changes patched to the state are serialized to storage.\n\nYou can configure custom serializers and storage objects using the `StorageStatefulConfig\u003cTState extends {}\u003e` interface as the third parameter.\n\n```typescript\n/**\n * Configuration options for the StorageStateful class.\n */\nexport interface StorageStatefulConfig\u003cTState extends {}\u003e {\n    /**\n     * A deserialize function that converts a string into a state object.\n     */\n    deserializer?: (state: string) =\u003e TState;\n\n    /**\n     * A serialize function that converts a state object into a string.\n     */\n    serializer?: (state: TState) =\u003e string;\n\n    /**\n     * The storage object to use (can be localStorage or sessionStorage).\n     */\n    storage?: Storage;\n}\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactgular%2Fstateful","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freactgular%2Fstateful","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactgular%2Fstateful/lists"}