{"id":37197188,"url":"https://github.com/niryo/controllerim","last_synced_at":"2026-01-14T22:55:43.745Z","repository":{"id":57206657,"uuid":"111235816","full_name":"Niryo/controllerim","owner":"Niryo","description":"A state management library for React","archived":true,"fork":false,"pushed_at":"2022-04-08T12:50:03.000Z","size":2410,"stargazers_count":214,"open_issues_count":0,"forks_count":5,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-09-22T01:45:43.572Z","etag":null,"topics":["react","state-management"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/Niryo.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":"2017-11-18T20:12:55.000Z","updated_at":"2024-08-05T04:59:32.000Z","dependencies_parsed_at":"2022-09-08T14:22:25.250Z","dependency_job_id":null,"html_url":"https://github.com/Niryo/controllerim","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Niryo/controllerim","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Niryo%2Fcontrollerim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Niryo%2Fcontrollerim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Niryo%2Fcontrollerim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Niryo%2Fcontrollerim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Niryo","download_url":"https://codeload.github.com/Niryo/controllerim/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Niryo%2Fcontrollerim/sbom","scorecard":{"id":101888,"data":{"date":"2025-08-11","repo":{"name":"github.com/Niryo/controllerim","commit":"1482a2e62a26f04469974b670084c40b96f93ebe"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"project is archived","details":["Warn: Repository is archived."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/18 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 14 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-15T10:18:56.172Z","repository_id":57206657,"created_at":"2025-08-15T10:18:56.172Z","updated_at":"2025-08-15T10:18:56.172Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28437349,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T22:37:52.437Z","status":"ssl_error","status_checked_at":"2026-01-14T22:37:31.496Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["react","state-management"],"created_at":"2026-01-14T22:55:43.155Z","updated_at":"2026-01-14T22:55:43.706Z","avatar_url":"https://github.com/Niryo.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Controllerim\n\nA simple, clean and well structured state management library for react\n\n[![npm version](https://img.shields.io/npm/v/controllerim.svg)](https://www.npmjs.com/package/controllerim)\n\n## Installation\n\n`npm install controllerim --save`\n\n## Migrating from Controllerim v2 to v3\nThe migration process should be very easy. Follow the docs and the example project for understanding the new API.\n\n## Basic usage example\n\n\n\nInside `ParentController.js`:\n\n```javascript\nimport { controller } from 'controllerim';\n\nclass _ParentController {\n  constructor() {\n    this.state = {\n      message: 'hello' \n    };\n  }\n  getMessage() {\n    return this.state.message;\n  }\n  setMessage(value) {\n    this.state.message = value;\n  }\n}\n\nexport const ParentController = controller(_ParentController);\n```\n\nInside `Parent.jsx`:\n\n```javascript\nimport React, { Component } from 'react';\nimport { observer } from 'controllerim';\nimport { ParentController } from './ParentController';\n\nclass Parent extends Component {\n  constructor(props) {\n    super(props);\n    this.controller = ComponentController.create(); //returns a fresh controller instance\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003ch1\u003e{this.controller.getMessage()}\u003c/h1\u003e\n        \u003cChild/\u003e\n        \u003cbutton onClick={() =\u003e this.controller.setMessage('hello world!')}\u003eClick me to change message\u003c/button\u003e\n      \u003c/div\u003e\n    );\n  }\n};\n\nexport default observer(Parent);\n```\n\nInside `Child.jsx`:\n\n```javascript\nimport React, { Component } from 'react';\nimport { observer} from 'controllerim';\nimport {ParentController} from './ParentController'\n\nclass Child extends Component {\n  constructor(props){\n    super(props);\n    this.parentController = ParentController.getInstance(); //returns an existing instance of the parentController. You could supply an id if you you have more than one instances of the parent controller.\n  }\n \n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003cspan\u003eThis is a message from parent: {this.parentController.getMessage()}\u003c/span\u003e\n      \u003c/div\u003e\n    );\n  }\n};\n\nexport default observer(Child);\n```\n### Example project\n\nHere is a [Simple example project](https://niryo.github.io/controllerim/)\nYou can see the source code under the example folder: [demo-app/src](demo-app/src)\nIf you want to run it locally:\nAfter cloning the repository, navigate to the demo-app folder and type in your terminal:\n\n```\nnpm install\nnpm start\n```\n\n## How\n\nControllerim utilizes [Mobx](https://github.com/mobxjs/mobx) behind the scenes. You don't need to learn Mobx in order to use Controllerim, but a basic understanding of Mobx is recommended.\n\n## Api\n\n### `controller(controllerClass)`\n##### Arguments:\n* **controllerClass**: any es6 class with a state member.\n##### Returns:\n* **Object: { create(), getInstance() }**: an object with two factory methods for getting a new controller instance \n\nA controller is a plain Javascript class that holds a  **state** and methods for manipulating the state.\nAll the methods of the controller are smartly memoized and computed, thus if you do some heavy calculation, it will be re-calculated when really needed.\n\nThe observers (React Components that you wrapped within `observer`) will react to any change in the state, even changes of deep nested properties.\n\n#### `create(id?: string (default: 'globalInstance') )`:\n\nReturns a new instance of the given controller. You should use this method when you know for sure that you need a fresh instance and not an existing one (most of the time you should prefer `create` over `getInstance`). You can pass an `id`, for being used later by getInstance.\n\n#### `getInstance(id?: string (default: 'globalInstance'))`:\nReturns an existing instance of the given controller, or a new one if there isn't any existing instance yet. If you don't supply an `id`, the return value will be the default global instance.\n\n\n#### controller Usage example:\n\n```javascript\nimport {controller} from 'controllerim';\n\nclass _AppController {\n  constructor() {\n    this.state = {totalNotesCount: 2};                                 \n  }\n\n  getTotalNotesCount() {\n    return this.state.totalNotesCount;\n  }\n\n  increaseCounter() {\n    this.state.totalNotesCount++;\n  }\n}\n\nexport const AppController = controller(_AppController);\n```\n\nYour React component will create an instance of the controller like this: \n\n```javascript\nimport {AppController} from 'controllerim';\n\nclass App extends React.Component {\n  constructor(props) {\n    super(props);\n    this.controller = AppController.create();\n  }\n\n  render(){\n    \u003cdiv\u003e\n      \u003cdiv\u003e{this.controller.getTotalNotesCount()}\u003c/div\u003e\n      \u003cdiv onPress={() =\u003e this.controller.increaseCounter()}\u003eclick me\u003c/div\u003e\n    \u003c/div\u003e\n  }\n}\n```\n\n### `useController(controllerInstance)`\n\nAllows you to use controller inside a functional component. Note that you still have to wrap your functional component within `observer`.\n\n```javascript\nimport React from 'react';\nimport {observer, useController} from 'controllerim';\nimport {FunctionalComponentController} from './TestComponentController';\n\nexport const FunctionalComponent = observer(() =\u003e {\n  const controller = useController(FunctionalComponentController.create());\n  return (\n    \u003cdiv\u003e\n      \u003cdiv\u003e{controller.getUserName()}\u003c/div\u003e\n      \u003cdiv onClick={() =\u003e controller.changeUserName()}\u003eclick me\u003c/div\u003e\n    \u003c/div\u003e\n  );\n});\n```\n### `observer(ReactComponent)`\n\nTo become reactive, every React component that uses a controller, should be wrapped within `observer`. \n\n```javascript\nimport {observer} from 'controllerim';\n\nexport const SomeSmartComponent = observer(class extends React.Component {\n...\n})\n```\n\n### `store(storeClass)`\nA store is just a global singleton controller that is not conceptually bound to any specific component. \n\ninside `AppStore.js`:\n```javascript\n  import {store} from 'controllerim';\n\n  class _AppStore {\n    constructor(){\n      this.state = {useName: 'bla'};\n    }\n\n    getUserName() {\n      return this.state.userName;\n    }\n  }\n\n  export const AppStore = store(_AppStore);\n```\n\nInside `component.jsx`:\n\n```javascript\nimport React from 'react';\nimport {observer} from 'controllerim'\nimport {AppStore} from './AppStore';\n\nclass SomeComponent extends React.Component {\n  render(){\n    \u003cdiv\u003e{AppStore.getUserName()}\u003c/div\u003e // \u003c== The component will re-render on any change in getUserName\n  }\n}\n\nexport default observer(SomeComponent);\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniryo%2Fcontrollerim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniryo%2Fcontrollerim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniryo%2Fcontrollerim/lists"}