{"id":16286386,"url":"https://github.com/kekekeks/nobservable","last_synced_at":"2025-03-20T02:31:38.474Z","repository":{"id":142895720,"uuid":"146847111","full_name":"kekekeks/NObservable","owner":"kekekeks","description":"MobX like observable state management library with Blazor support","archived":false,"fork":false,"pushed_at":"2019-06-06T14:08:16.000Z","size":230,"stargazers_count":68,"open_issues_count":3,"forks_count":7,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-03-11T12:40:33.948Z","etag":null,"topics":["blazor","csharp","mobx","state-management","ui","web"],"latest_commit_sha":null,"homepage":"","language":"C#","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/kekekeks.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}},"created_at":"2018-08-31T05:47:07.000Z","updated_at":"2024-11-06T16:56:17.000Z","dependencies_parsed_at":"2023-06-09T00:45:38.463Z","dependency_job_id":null,"html_url":"https://github.com/kekekeks/NObservable","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekekeks%2FNObservable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekekeks%2FNObservable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekekeks%2FNObservable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekekeks%2FNObservable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kekekeks","download_url":"https://codeload.github.com/kekekeks/NObservable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244047544,"owners_count":20389203,"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":["blazor","csharp","mobx","state-management","ui","web"],"created_at":"2024-10-10T19:43:00.280Z","updated_at":"2025-03-20T02:31:38.098Z","avatar_url":"https://github.com/kekekeks.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IL-instrumentation-based observables for C#\n\nThe idea is to implement something like MobX for .NET and to mirror its API when it's possible and makes sense. Library is originally intended to be used with Blazor, but isn't limited to that, so Blazor-specific bits live in a separate package.\n\nFor now library supports:\n\n- [observable properties](#observable-attribute)\n- ObservableList\u003cT\u003e\n- [Autorun](#autorun)\n- [When](#when)\n- [RunInAction](#runinaction)\n- \"@observer\" **Blazor** components (see [usage with blazor](#usage-with-blazor))\n\nMissing features (aka TODO):\n\n- [computed properties](https://mobx.js.org/refguide/computed-decorator.html)\n- [reaction](https://mobx.js.org/refguide/reaction.html)\n- [@action decorator](https://mobx.js.org/refguide/action.html)\n\n\n# Usage\n\n## Installation\n\nSee also [Fody usage](https://github.com/Fody/Fody#usage).\n\n### NuGet installation\n\nInstall the [NObservable NuGet package](https://nuget.org/packages/NObservable/)\n\n```\ndotnet add package NObservable\n```\n\n\n### Add to FodyWeavers.xml\n\nAdd `\u003cNObservable/\u003e` to [FodyWeavers.xml](https://github.com/Fody/Fody#add-fodyweaversxml)\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\" ?\u003e\n\u003cWeavers\u003e\n  \u003cNObservable/\u003e\n\u003c/Weavers\u003e\n```\n\n## API\n\n### [Observable] attribute\n\n`[Observable]` instructs to instrument either one property or entire class. \nProperty access will be tracked by NObservable.\n\nWorks like [@observable decorator](https://mobx.js.org/refguide/observable-decorator.html) from MobX but can be also applied to entire class\n\n```cs\n[Observable]\nclass Foo\n{\n    public int Prop1 { get; set; }\n    public int Prop2 { get; set; }\n}\n```\n\n\n```cs\nclass Bar\n{\n    [Observable]\n    public int Foo { get; set; }\n    public int NotTracked{ get; set; }\n}\n\n``` \n\n\n### Autorun\n\nWorks like [autorun](https://mobx.js.org/refguide/autorun.html) from MobX. \nIt runs provided callback once and records all read property access to observable objects. \nIf any of observed properties changes, callback will be run again and new property access list will be recorded\n\n\n```cs\n\nvar o = new Foo{Prop1 = 1, Prop2 = 1};\nConsole.WriteLine(\"Initial run\");\nObserve.Autorun(() =\u003e {\n    if(o.Prop1 == 3)\n        Console.WriteLine($\"Prop1: {o.Prop1} Prop2: {o.Prop2}\");\n    else\n        Console.WriteLine($\"Prop1: {o.Prop1}\");    \n});\nConsole.WriteLine(\"Setting Prop1 = 2, expecting update\");\no.Prop1 = 2;\nConsole.WriteLine(\"Setting Prop2 = 2, it wasn't read last time, not expecting update\");\no.Prop2 = 2;\nConsole.WriteLine(\"Setting Prop1 = 3, expecting update\");\no.Prop1 = 3;\nConsole.WriteLine(\"Setting Prop2 = 3, it was read last time, expecting update\");\no.Prop2 = 3;\n\n```\n\nConsole output:\n\n```\nInitial run\nProp1: 1\nSetting Prop1 = 2, expecting update\nProp1: 2\nSetting Prop2 = 2, it wasn't read last time, not expecting update\nSetting Prop1 = 3, expecting update\nProp1: 3 Prop2: 2\nSetting Prop2 = 3, it was read last time, expecting update\nProp1: 3 Prop2: 3\n```\n\n\n### When\n\nWorks like [when](https://mobx.js.org/refguide/autorun.html) from MobX. \nEither returns a task that completes when observed condition is met or runs a provided callback:\n\n```cs\n\nawait Observe.When(() =\u003e o.Prop1 == 5);\n\nObserve.When(() =\u003e o.Prop2 == 5, () =\u003e Console.WriteLine(\"callback\"));\n\n```\n\n### RunInAction\n\nWorks like [runInAction](https://mobx.js.org/best/actions.html#the-runinaction-utility) from MobX.\nGroups multiple property updates so change reactions won't be triggered on *each* property set call.\n\nProper method instrumentation ([@action decorator](https://mobx.js.org/refguide/action.html) alternative)\nisn't implemented **yet**, but unlike MobX it would be possible to make it properly work with `async` functions.\n\n```cs\nvar o = new Foo{Prop1 = 1};\nObserve.Autorun(() =\u003e Console.WriteLine(o.Prop1));\nObserve.RunInAction(() =\u003e {\n    o.Prop1++;\n    o.Prop1++;\n    o.Prop1 = 5;\n    \n});\n\n```\n\nConsole output:\n```\n1\n5\n```\n\n\n## Usage with Blazor\n\nInstall the [NObservable.Blazor NuGet package](https://nuget.org/packages/NObservable.Blazor/) \nand add [NObservable to FodyWeavers](#add-to-fodyweaversxml)\n\n```\ndotnet add package NObservable\n```\n\nAdd UseNObservable to your `Startup.cs`:\n\n```cs\npublic void Configure(IBlazorApplicationBuilder app)\n{\n    app.UseNObservable(); // \u003c---------------\n    app.AddComponent\u003cApp\u003e(\"app\");\n}\n```\n\nAdd `@using NObservable.Blazor` to `_ViewImports.cshtml`.\n\n\nAdd `@implements IObserverComponent` at the top of your blazor component\n\n\n\nNow your component should update if any observable properties used during the previous render are changed. \nNote, that NObservable adds its own `ShouldRender` implementation if your component doesn't have one already,\nso automatic update after input events won't happen. \nTo automatically update on local property changes decorate your local properties with `[Observable]`\n\n\n### Some kind of example app\n\n`AppModel.cs`:\n\n```cs\n[Observable]\npublic class AppModel\n{\n    public int Counter { get; set; }\n\n    public AppModel()\n    {\n        Tick();\n    }\n\n    async void Tick()\n    {\n        while (true)\n        {\n            Counter++;\n            await Task.Delay(1000);\n        }\n    }\n}\n\n```\n\n`Startup.cs`:\n```cs\npublic class Startup\n{\n    public void ConfigureServices(IServiceCollection services)\n    {\n        services.AddSingleton\u003cAppModel\u003e();\n    }\n\n    public void Configure(IBlazorApplicationBuilder app)\n    {\n        app.UseNObservable();\n        app.AddComponent\u003cApp\u003e(\"app\");\n    }\n}\n```\n\n```cshtml\n@page \"/\"\n@implements IObserverComponent\n@inject AppModel model\n\n\u003ch1\u003eCounter demo\u003c/h1\u003e\n\n\nCounter: @(model.Counter)\n```\n\nCounter should tick automatically\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkekekeks%2Fnobservable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkekekeks%2Fnobservable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkekekeks%2Fnobservable/lists"}