{"id":13493327,"url":"https://github.com/BrodaNoel/duix","last_synced_at":"2025-03-28T11:32:23.294Z","repository":{"id":33799280,"uuid":"162633511","full_name":"BrodaNoel/duix","owner":"BrodaNoel","description":"A State Manager focused on KISS and Pareto's Principle","archived":false,"fork":false,"pushed_at":"2025-02-04T16:22:27.000Z","size":152,"stargazers_count":53,"open_issues_count":5,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-22T22:17:28.394Z","etag":null,"topics":["callback","callbacks","kiss","manager","pareto","pareto-principle","redux","state","state-management","state-manager","statemanager","vuex"],"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/BrodaNoel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"BrodaNoel"}},"created_at":"2018-12-20T21:32:48.000Z","updated_at":"2025-03-15T14:31:18.000Z","dependencies_parsed_at":"2024-01-15T20:47:44.070Z","dependency_job_id":"e41c2b0d-4e6d-4d12-901c-494c6a7e755e","html_url":"https://github.com/BrodaNoel/duix","commit_stats":{"total_commits":66,"total_committers":4,"mean_commits":16.5,"dds":"0.18181818181818177","last_synced_commit":"7ba984077e437f0d097217d7e1a841081d9b9ced"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrodaNoel%2Fduix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrodaNoel%2Fduix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrodaNoel%2Fduix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrodaNoel%2Fduix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BrodaNoel","download_url":"https://codeload.github.com/BrodaNoel/duix/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246021249,"owners_count":20710905,"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":["callback","callbacks","kiss","manager","pareto","pareto-principle","redux","state","state-management","state-manager","statemanager","vuex"],"created_at":"2024-07-31T19:01:14.238Z","updated_at":"2025-03-28T11:32:23.005Z","avatar_url":"https://github.com/BrodaNoel.png","language":"JavaScript","funding_links":["https://github.com/sponsors/BrodaNoel"],"categories":["JavaScript"],"sub_categories":[],"readme":"# DUIX\n\nA Simple library to keep vars on sync between components (or whatever). It's just a matter of callbacks. Use it as you want.\n\n## The `duix` approach\n\n`duix` just have a state that is just a plain (private) object, and some listeners (publish-subscribers) that are gonna be called every time the subscribed-value change.\nIt's just a Publish Subscriber lib + a private object (the state). Duix clone the received object, and send a cloned object to the subscribers, in order to keep the immutability of the store.\n\n# API doc\n\nWith examples. People need examples!\n\n- `duix.get('user')`: Returns (it's NOT a promise) the `user` value. This value is safe to be mutated. It's not going to mutate the state.\n- `duix.set('user', { name: 'Noel' })`: This set the `user` value. It can be ab Object, Array, null, whatever. You can safely mutate the object after setting it. It's not going to mutate the state.\n- `duix.subscribe('user', (newValue, oldValue) =\u003e { /* ... */ })`: Subscribe a callback on every change made in `user`. A change on `user` can be made only by calling `duix.set('user', {\\* ... *\\})` with a different value that the value is currently on the state. This function also returns a function that if you call it, you unsubcribe to the changes (example below).\n\nHere the unsubscribe example:\n\n```js\n// Subscribe\nconst unsubscriber = duix.subscribe('user', (newValue, oldValue) =\u003e {\n  /* ... */\n});\n\n// Unsubscribe\nunsubscriber();\n```\n\nSee below for some advanced usages.\n\n## The Counter Example\n\n1. `Buttons` component is gonna add or subtract.\n2. `Viewer` component is gonna show the value\n\n```js\n// index.js\nimport duix from 'duix';\n\n// Set `null` as default `user` value\nduix.set('githubStars', 0);\n\nclass App extends Component {\n  // ...\n}\n```\n\n```js\n// Buttons.js\nimport duix from 'duix';\n\nclass Buttons extends Component {\n  handleAdd = () =\u003e {\n    const currentValue = duix.get('githubStars');\n    duix.set('githubStars', currentValue + 1);\n  };\n\n  handleSubtract = () =\u003e {\n    const currentValue = duix.get('githubStars');\n    duix.set('githubStars', currentValue - 1);\n  };\n\n  // ...\n}\n```\n\n```js\n// Viewer.js\nimport duix from 'duix';\n\nclass Viewer extends Component {\n  unsubscribe = [];\n  state = {\n    githubStars: duix.get('githubStars'), // get initial value\n  };\n\n  componentDidMount() {\n    this.unsubscribe[0] = duix.subscribe('githubStars', this.onStarsChange);\n  }\n\n  componentWillUnmount() {\n    this.unsubscribe[0]();\n  }\n\n  onStarsChange = githubStars =\u003e {\n    this.setState({ githubStars });\n  };\n\n  render() {\n    return \u003cdiv className=\"Viewer\"\u003e{this.state.githubStars} stars\u003c/div\u003e;\n  }\n}\n```\n\nSo, could you understand what happened there? Only 3 things on `duix`:\n\n1. Someone needs to set the default value\n2. Someone is gonna get the initial value, and also `subscribe` to any change\n3. Someone is gonna `set` the new value every time it have to be changed.\n\n## The Login Example\n\n1. The main file in the app defines the initial value for the `user` object.\n2. The `Header` component is subscribed to the changes of `user` (because if the `user` object is not `null`, it's because the user is logged).\n3. The `Login` component is gonna call a function that is gonna do the API call to check if the credentials are OK.\n4. The `LogOut` component is gonna logout the user. :shrug:\n\nThe code:\n\n```js\n// index.js\nimport duix from 'duix';\n\n// Set `null` as default `user` value\nduix.set('user', null);\n\nclass App extends Component {\n  // ...\n}\n```\n\n```js\n// Login.js\nimport duix from 'duix';\n// Let's suppose this `actions` is an object with all the functions necessary to login an user\nimport { loginWithCredentials } from 'actions';\n\nclass Login extends Component {\n  handleLogin = (email, password) =\u003e {\n    // The `Login` component is not gonna change the `user` object. Instead, the `loginWithCredentials` is gonna do it.\n    loginWithCredentials(email, password);\n  };\n\n  // ...\n}\n```\n\n```js\n// Logout.js\nimport duix from 'duix';\n\nclass Logout extends Component {\n  handleLogout = () =\u003e {\n    duix.set('user', null);\n  };\n\n  // ...\n}\n```\n\n```js\n// actions.js\nimport duix from 'duix';\n\nexport default {\n  loginWithCredentials: (email, password) =\u003e {\n    fetch(\n      'http://example.com/api/login'\n      // ...\n    )\n      .then(r =\u003e r.json())\n      .then(user =\u003e {\n        /**\n         * Whatever the backend send us, let's set it.\n         *\n         * Let's suppose the backend send `null` if the credentials were wrong,\n         * or the proper `user` object if the credentials were OK.\n         */\n        duix.set('user', user);\n      });\n  },\n};\n```\n\n```js\n// Header.js\nimport duix from 'duix';\n\nclass Header extends Component {\n  unsubscribe = [];\n  state = {\n    user: null,\n  };\n\n  componentDidMount() {\n    // Let's subscribe to the `user` changes\n    this.unsubscribe[0] = duix.subscribe('user', this.onUserChange);\n  }\n\n  componentWillUnmount() {\n    // Let's unsubscribe.\n    this.unsubscribe[0]();\n  }\n\n  onUserChange = user =\u003e {\n    this.setState({ user });\n  };\n\n  render() {\n    return \u003cdiv className=\"Header\"\u003e{this.state.user \u0026\u0026 `Hello ${this.state.user.name}`}\u003c/div\u003e;\n  }\n}\n```\n\nSo, could you understand what happened there? Only 3 things on `duix`:\n\n1. Someone needs to set the default value\n2. Someone is gonna `subscribe` to a value change, or unsubscribe when component unmount.\n3. Someone is gonna `set` the new value every time it changes\n\n## Advanced options/usages\n\nWhen subscribing to a value, you can choose special behaviors by passing an object as third parameter:\n\n```lang=javascript\nduix.subscribe(key, callback, {\n  fireImmediately: false\n});\n```\n\n| option          | default value | comment                                                              |\n| --------------- | ------------- | -------------------------------------------------------------------- |\n| fireImmediately | false         | Should duix callback immediately with the value currently in memory? |\n\n## Why was it created?\n\nBecause some ~most~ of the current State Managers libs add too unnecessary complexity (even in the learning curve, or arch, or high coupling between components).\n\nThe idea of `duix` is to reuse some old knowledge to solve only one simple problem: Keep 2 components on sync.\n\nThere are 2 things that I keep on mind while working:\n\n1. **KISS principle**: Keep it simple, stupid.\n2. **Pareto's principle**: The 80% and 20%. The 80% of your bugs, are gonna be always the same 2 or 3 issues that you always see in every project.\n\nThe KISS principle is very clear, but I believe the Pareto principle deserves more details:\n\nI believe that if you added a State Manager in 10 projects, you may added it 8 times just to solve 1 issue: \"Keep a couple of vars on sync between components\".\nOn another hand, you also added it 2 for solving tons of issues that it absolutelly worth it.\n\nBut, what about those 8 times that you added, let's say, Redux, only to keep 1 var on sync? You only needed a global state var and a callback, but you added the whole Redux library (complexity, a lot of complexity my friend).\n\nThe idea of `duix` is to cover those 8 times that you added Redux only because you needed to keep on sync vars between components. Just that. There is a global `state` object, where you `set`, or `get` values, and you can `subscribe` or `unsubscribe` of their changes. Every time someone `set` a new value, all the subscribers are gonna be called receiving the new and the old value.\n\nIf your team is not feeling very well with the current State Managers complexity (you may know a lot of devs with that feeling), I'd say that you should try this tool.\n\n\"That's all, folks\"\n\nPS: 10 minutes ago it was Christmas. This is my gift for te community.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBrodaNoel%2Fduix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FBrodaNoel%2Fduix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBrodaNoel%2Fduix/lists"}