{"id":13451142,"url":"https://github.com/pshomov/reducto","last_synced_at":"2026-01-14T04:59:11.270Z","repository":{"id":50375370,"uuid":"43943627","full_name":"pshomov/reducto","owner":"pshomov","description":"A port of Redux to .NET","archived":false,"fork":false,"pushed_at":"2022-07-28T15:55:24.000Z","size":27,"stargazers_count":76,"open_issues_count":4,"forks_count":5,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-09-30T11:02:35.628Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/pshomov.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":"2015-10-09T08:46:22.000Z","updated_at":"2024-05-06T02:21:54.000Z","dependencies_parsed_at":"2022-07-30T23:08:04.024Z","dependency_job_id":null,"html_url":"https://github.com/pshomov/reducto","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pshomov/reducto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pshomov%2Freducto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pshomov%2Freducto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pshomov%2Freducto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pshomov%2Freducto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pshomov","download_url":"https://codeload.github.com/pshomov/reducto/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pshomov%2Freducto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28410025,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-07-31T07:00:48.859Z","updated_at":"2026-01-14T04:59:11.256Z","avatar_url":"https://github.com/pshomov.png","language":"C#","funding_links":[],"categories":["Other languages","C# #"],"sub_categories":["Chrome Extensions"],"readme":"# Reducto is a port of [Redux](http://rackt.github.io/redux/) to .NET\n\n[![Build Status](https://img.shields.io/travis/pshomov/reducto.svg?style=flat-square)](https://travis-ci.org/pshomov/reducto)\n[![NuGet Release](https://img.shields.io/nuget/v/Reducto.svg?style=flat-square)](https://www.nuget.org/packages/Reducto/)\n\n## What is Reducto?\n\nReducto is a keeper of the state for your app. It helps to organize the logic that changes that state. Really useful for GUI apps in combination with(but not limited to) MVVM, MVC, MVP etc. \n\n|Metric|Value|\n|-------|-----|\n|lines of code| ~260|\n|dependencies| 0 |\n|packaging | [NuGet PCL](https://www.nuget.org/packages/Reducto/) |\n\n## Installation\n\nIn Package Manager Console run\n\n```\nPM\u003e Install-Package Reducto\n```\n\n## Key concepts\n\n - **Action** - an object which describes what has happened - LoggedIn, SignedOut, etc. The object contains all the information relevant to the action - username, password, status, etc. Usually there are many actions in an app. \n - **Reducer** - a side-effect free function that receives the current state of your app and an `action`. If the reducer does not know how to handle the `action` it should return the state as is. If the reducer can handle the `action` it 1.) makes a copy of the state 2.) it modifies it in response to the `action` and 3.) returns the copy.\n - **Store** - it is an object that contains your app's state. It also has a `reducer`. We _dispatch_ an `action` to the `store` which hands it to the `reducer` together with the current app state and then uses the return value of the `reducer` as the new state of the app. There is only one `store` in your app. It's created when your app starts and gets destroyed when your app quits. Your MVVM view models can _subscribe_ to be notified when the state changes so they can update themselves accordingly. \n - **Async action** - a function that may have side effects. This is where you talk to your database, call a web service, navigate to a view model, etc. `Async actions` can also dispatch `actions` (as described above). To execute an `async action` it needs to be _dispatched_ to the `store`.\n - **Middleware** - these are functions that can be hooked in the `store` dispatch mechanism so you can do things like logging, profiling, authorization, etc. It's sort of a plugin mechanism which can be quite useful.\n\nDispatching an `action` to the store is **the only way to change its state**.\u003cbr\u003e\nDispatching an `async action` cannot change the state but it can dispatch `actions` which in turn can change the state.\n\n## How does one use this thing?\n\nHere is a short example of Reducto in action. Let's write an app that authenticates a user. \n\nFirst, let's define the `actions` that we will need:\n\n```c#\n// Actions\n\npublic struct LoginStarted \n{ \n    public string Username; \n}\n\npublic struct LoginFailed {}\n\npublic struct LoginSucceeded \n{\n    public string Token;\n}\n```\nNext is the state of our app \n\n```c#\n// State\n\npublic enum LoginStatus \n{\n    LoginInProgress, LoggedIn, NotLoggedIn\n}\n\npublic struct AppState\n{\n    public LoginStatus Status;\n    public String Username;\n    public String Token;\n}\n```\n\nHere is how the `actions` change the state of the app\n\n```c#\nvar reducer = new SimpleReducer\u003cAppState\u003e()\n    .When\u003cLoginStarted\u003e((state, action) =\u003e {\n        state.Username = action.Username;\n        state.Token = \"\";\n        state.Status = LoginStatus.LoginInProgress;\n        return state;\n    })\n    .When\u003cLoginSucceeded\u003e((state, action) =\u003e {\n        state.Token = action.Token;\n        state.Status = LoginStatus.LoggedIn;\n        return state;\n    })\n    .When\u003cLoginFailed\u003e((state, action) =\u003e {\n        state.Status = LoginStatus.NotLoggedIn;\n        return state;\n    });\n\nvar store = new Store\u003cAppState\u003e(reducer);\n```\nNow let's take a moment to see what is going on here. We made a `reducer` using a builder and define how each `action` changes the state. This `reducer` is provieded to the `store` so the store can use it whenever an `action` is dispatched to it. Makes sense so far? I hope so ;)\n\nNow let's see what is dispatching `actions` to the `store`. One can do that directly but more often then not it will be done from inside an `async action` like this one\n```c#\nvar loginAsyncAction = store.asyncAction(async(dispatch, getState) =\u003e {\n    dispatch(new LoginStarted{Username = \"John Doe\"});\n\n    // faking authentication of user\n    await Task.Delay(500);\n    var authenticated = new Random().Next() % 2 == 0;\n\n    if (authenticated) {\n        dispatch(new LoginSucceeded{Token = \"1234\"});\n    } else {\n        dispatch(new LoginFailed());\n    }\n    return  authenticated;\n});\n```\nA lot going on here. The `async action` gets a _dispatch_ and a _getState_ delegates. The latter one is not used in our case but the former is used a lot. We dispatch an action to signal the login process has started and then again after it has finished and depending on the outcome of the operation. How do we use this `async action`?\n```c#\nstore.Dispatch(loginAsyncAction);\n// or if you need to know the result of the login you can do also\nvar logged = await store.Dispatch(loginAsyncAction);\n```\n\nFor more examples and please checkout the links below in the Resources section\n\n## Resources\n\nA couple of links on my blog\n \n - [Better MVVM with Xamarin Forms](http://pshomov.github.io/better-mvvm-with-xamarin-forms/)\n - [Compartmentalizing logic](http://pshomov.github.io/compartmentalizing-logic/)\n\n## What about the name?\n\n[It is pure magic ;-)](https://en.wikibooks.org/wiki/Muggles%27_Guide_to_Harry_Potter/Magic/Reducto#Overview)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpshomov%2Freducto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpshomov%2Freducto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpshomov%2Freducto/lists"}