{"id":28625340,"url":"https://github.com/forevolve/stater","last_synced_at":"2026-04-11T04:33:56.876Z","repository":{"id":43375732,"uuid":"298157763","full_name":"ForEvolve/StateR","owner":"ForEvolve","description":"Stator is a simple, DI-oriented, Redux-inspired or Model-View-Update (MVU) **experiment** using C# 9.0 (preview) for .NET","archived":false,"fork":false,"pushed_at":"2022-03-04T15:20:22.000Z","size":525,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-12-02T19:49:31.115Z","etag":null,"topics":["blazor","blazor-webassembly","dotnet","mvu","net","net5","netcore","redux","xamarin"],"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/ForEvolve.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}},"created_at":"2020-09-24T03:20:38.000Z","updated_at":"2024-09-16T14:16:58.000Z","dependencies_parsed_at":"2022-08-29T19:12:04.862Z","dependency_job_id":null,"html_url":"https://github.com/ForEvolve/StateR","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ForEvolve/StateR","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ForEvolve%2FStateR","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ForEvolve%2FStateR/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ForEvolve%2FStateR/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ForEvolve%2FStateR/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ForEvolve","download_url":"https://codeload.github.com/ForEvolve/StateR/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ForEvolve%2FStateR/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259427060,"owners_count":22855564,"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","blazor-webassembly","dotnet","mvu","net","net5","netcore","redux","xamarin"],"created_at":"2025-06-12T08:10:21.656Z","updated_at":"2025-12-30T22:36:39.867Z","avatar_url":"https://github.com/ForEvolve.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Stator\n\nStator is a simple, DI-oriented, Redux-inspired or Model-View-Update (MVU) **experiment** using C# 9.0.\nIt works well with Blazor and [MobileBlazorBindings](https://github.com/xamarin/MobileBlazorBindings),\nincluding sharing states between the Xamarin part and the Blazor part of a hybrid mobile app.\nIt should also work with any other .NET stateful client model.\n\n\u003e As of 2021-04-08, the project does not support .NET Standard 2.0, only .NET 5+\n\nThis project uses:\n\n-   C# 9 record classes to ensure immutability and to simplify reducers.\n-   Dependency Injection to manage states (and everything else)\n\n# How to install?\n\n| Name                                           | NuGet.org                                                                                                                              | feedz.io                                                                                                                                                                                                                                         |\n| ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `dotnet add package StateR`                    | [![NuGet.org](https://img.shields.io/nuget/vpre/StateR)](https://www.nuget.org/packages/StateR/)                                       | [![feedz.io](https://img.shields.io/badge/endpoint.svg?url=https%3A%2F%2Ff.feedz.io%2Fforevolve%2Fstator%2Fshield%2FStateR%2Flatest)](https://f.feedz.io/forevolve/stator/packages/StateR/latest/download)                                       |\n| `dotnet add package StateR.Blazor`             | [![NuGet.org](https://img.shields.io/nuget/vpre/StateR.Blazor)](https://www.nuget.org/packages/StateR.Blazor/)                         | [![feedz.io](https://img.shields.io/badge/endpoint.svg?url=https%3A%2F%2Ff.feedz.io%2Fforevolve%2Fstator%2Fshield%2FStateR.Blazor%2Flatest)](https://f.feedz.io/forevolve/stator/packages/StateR.Blazor/latest/download)                         |\n| `dotnet add package StateR.Blazor.Experiments` | [![NuGet.org](https://img.shields.io/nuget/vpre/StateR.Blazor.Experiments)](https://www.nuget.org/packages/StateR.Blazor.Experiments/) | [![feedz.io](https://img.shields.io/badge/endpoint.svg?url=https%3A%2F%2Ff.feedz.io%2Fforevolve%2Fstator%2Fshield%2FStateR.Blazor.Experiments%2Flatest)](https://f.feedz.io/forevolve/stator/packages/StateR.Blazor.Experiments/latest/download) |\n| `dotnet add package StateR.Experiments`        | [![NuGet.org](https://img.shields.io/nuget/vpre/StateR.Experiments)](https://www.nuget.org/packages/StateR.Experiments/)               | [![feedz.io](https://img.shields.io/badge/endpoint.svg?url=https%3A%2F%2Ff.feedz.io%2Fforevolve%2Fstator%2Fshield%2FStateR.Experiments%2Flatest)](https://f.feedz.io/forevolve/stator/packages/StateR.Experiments/latest/download)               |\n\n# Counter sample\n\nThe following snippet represent a feature, surrounding a counter, where you can `Increment`, `Decrement`,\nand `Set` the value of the `Count` property of that `Counter.State`. The snippet also include the\n`InitialState` of that counter.\n\n```csharp\nservices\n    .AddStateR(appAssembly)\n    .AddAsyncOperations() // Add support for Redux thunk-like helpers\n    .AddReduxDevTools() // Add support for Redux DevTools\n    .Apply()\n;\n```\n\n```csharp\nusing StateR;\n\nnamespace BlazorMobileHybridExperiments.Features\n{\n    public class Counter\n    {\n        public record State(int Count) : StateBase;\n\n        public class InitialState : IInitialState\u003cState\u003e\n        {\n            public State Value =\u003e new State(0);\n        }\n\n        public record Increment : IAction;\n        public record Decrement : IAction;\n\n        public class Reducers : IReducer\u003cState, Increment\u003e, IReducer\u003cState, Decrement\u003e\n        {\n            public State Reduce(State state, Increment action) =\u003e state with { Count = state.Count + 1 };\n            public State Reduce(State state, Decrement action) =\u003e state with { Count = state.Count - 1 };\n        }\n    }\n}\n```\n\nThen from a Blazor component that inherits from `StatorComponent`, we can dispatch those actions.\n\n```csharp\n@page \"/counter\"\n@inherits StateR.Blazor.StatorComponent\n@inject IState\u003cFeatures.Counter.State\u003e CounterState\n\n\u003ch1\u003eCounter\u003c/h1\u003e\n\u003cp\u003eCurrent count: @CounterState.Current.Count\u003c/p\u003e\n\u003cbutton class=\"btn btn-primary\" @onclick=\"@(async () =\u003e await DispatchAsync(new Features.Counter.Increment()))\"\u003e+\u003c/button\u003e\n\u003cbutton class=\"btn btn-primary\" @onclick=\"@(async () =\u003e await DispatchAsync(new Features.Counter.Decrement()))\"\u003e-\u003c/button\u003e\n```\n\n\u003e It is not needed to inherit from `StatorComponent`, a component (or any class) can manually subscribe to any `IState\u003cT\u003e`.\n\n# The origin\n\nI played around with a few other libraries and I was not 100% satisfied with how they did stuff.\nSo while playing around with MobileBlazorBindings and the new hybrid apps, I found that C# 9 records\nwere a great fit for this. I started experimenting with transforming immutable types (records) and\nended up creating this project.\n\n## Origin of the name\n\nThe name `StateR`, pronounced `Stator`, is inspired by `MediatR` that was initially used under the hood to mediate the commands.\n\n## Definition of a Stator\n\n\u003e The stator is the stationary part of a rotary system [...].\n\u003e Energy flows through a stator to or from the rotating component of the system.\n\nSource: [wikipedia](https://en.wikipedia.org/wiki/Stator)\n\n# Why Redux?\n\nAfter hearing about it for years, I read about it and found the concept brilliant, experimented with it, and adopted the idea.\n\n## What is different in this library?\n\nThis library is based on the concepts introduced by Redux, but .NET is not JavaScript and\n.NET Core is built around Dependency Injection (DI), so I decided to take advantage of that.\n\nThere is no type and no real DI in JavaScript, so it make sense that the folks there did not take\nthat into account when they built Redux.\n\n# Redux DevTools\n\nI based the Redux DevTools implementation on [Fluxor](https://github.com/mrpmorris/Fluxor/blob/master/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsInterop.cs),\nwhich is a similar project, that I used once.\nThat helped me lower the implementation time to connect Stator with Redux DevTools; thanks.\n\n# To be continued\n\n...\n\n# Found a bug or have a feature request?\n\nPlease open an issue and be as clear as possible; see _How to contribute?_ for more information.\n\n# How to contribute?\n\nIf you would like to contribute to the project, first, thank you for your interest, and please read [Contributing to ForEvolve open source projects](https://github.com/ForEvolve/ForEvolve.DependencyInjection/tree/master/CONTRIBUTING.md) for more information.\n\n## Contributor Covenant Code of Conduct\n\nAlso, please read the [Contributor Covenant Code of Conduct](https://github.com/ForEvolve/Toc/blob/master/CODE_OF_CONDUCT.md) that applies to all ForEvolve repositories.\n\n# Test (my clipboard/notes)\n\n## Coverlet code coverage\n\n-   `dotnet test /p:CollectCoverage=true` =\u003e coverage.json\n-   `dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura` =\u003e coverage.cobertura.xml\n-   `dotnet test --collect:\"XPlat Code Coverage\"` =\u003e TestResults/{GUID}/coverage.cobertura.xml\n\n-   `dotnet tool install -g dotnet-reportgenerator-globaltool`\n-   `reportgenerator -reports:coverage.cobertura.xml -targetdir:coveragereport -reporttypes:Html`\n\n```bash\ndotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura\nreportgenerator \"-reports:test\\**\\coverage.cobertura.xml\" -targetdir:coveragereport -reporttypes:Html\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforevolve%2Fstater","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fforevolve%2Fstater","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforevolve%2Fstater/lists"}