{"id":18872531,"url":"https://github.com/lilactown/flex","last_synced_at":"2025-04-07T15:09:57.906Z","repository":{"id":153748408,"uuid":"583185530","full_name":"lilactown/flex","owner":"lilactown","description":"flex is a reactive signal library for Clojure(Script)","archived":false,"fork":false,"pushed_at":"2025-01-04T17:55:45.000Z","size":1191,"stargazers_count":85,"open_issues_count":1,"forks_count":2,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-31T13:19:12.200Z","etag":null,"topics":["clojure","clojurescript","dataflow","reactive","reactive-programming","reactivity","signals","state-management"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lilactown.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-29T02:44:21.000Z","updated_at":"2025-03-18T15:05:25.000Z","dependencies_parsed_at":null,"dependency_job_id":"bc9c5dbc-d8dd-41c8-9b1d-48642c507cbc","html_url":"https://github.com/lilactown/flex","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/lilactown%2Fflex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lilactown%2Fflex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lilactown%2Fflex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lilactown%2Fflex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lilactown","download_url":"https://codeload.github.com/lilactown/flex/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247675607,"owners_count":20977378,"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":["clojure","clojurescript","dataflow","reactive","reactive-programming","reactivity","signals","state-management"],"created_at":"2024-11-08T05:30:27.552Z","updated_at":"2025-04-07T15:09:57.887Z","avatar_url":"https://github.com/lilactown.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# flex\n\nflex is a library for building computations using signals in Clojure(Script).\nIt gets its inspiration from [reagent](https://github.com/reagent-project/reagent)\nand its lineage ([reflex](https://github.com/lynaghk/reflex), KnockoutJS,\n[S.js](https://github.com/adamhaile/S)) as well as [SolidJS](https://www.solidjs.com/).\n\n## Install\n\nUsing git deps\n\n```clojure\ntown.lilac/flex {:git/url \"https://github.com/lilactown/flex\"\n                 :git/sha \"346bad039b560a62529a39af66e0afe35565b125\"\n```\n\n## Example\n\n```clojure\n(ns my-app.counter\n  \"A simple reactive counter\"\n  (:require\n   [town.lilac.flex :as flex]))\n\n;; a state container that can be changed manually\n(def counter (flex/source 0))\n\n;; a computation that updates when its dependencies change\n(def counter-sq (flex/signal (* @counter @counter)))\n\n;; an effect that runs side effects when its dependencies change\n(def prn-fx (flex/listen counter-sq prn))\n\n(counter 1)\n;; print: 1\n\n(doseq [_ (range 5)]\n  (counter inc))\n\n;; print: 4\n;; print: 9\n;; print: 16\n;; print: 25\n;; print: 36\n\n;; batch updates in transaction to avoid computing signals/effects until the end\n(flex/batch\n (counter inc)\n (counter inc)\n (counter inc)\n (counter inc))\n\n;; print: 100\n\n;; stop the effect from running and any dependent signals calculating\n(flex/dispose! prn-fx)\n\n(counter inc)\n\n;; nothing is printed\n```\n\n## Features\n\n- [x] JS and JVM platform support\n- [x] Reactive sources, signals and effects (`town.lilac.flex`)\n- [x] Functional transduce/transform/reduce (`town.lilac.flex.xform`)\n- [x] Memoized signal functions (`town.lilac.flex.memo`)\n- [x] `add-watch` \u0026 `remove-watch` support (`town.lilac.flex.atom`)\n- [x] Batching\n- [x] Error propagation to consumers\n- [x] Async support on JS (`town.lilac.flex.promise`)\n- [ ] Multiplexing / multithreaded scheduling on JVM\n\n### Differences from reagent\n\n#### Platform support\n\nflex supports Clojure on the JVM. Reagent is ClojureScript (JS) only\n\n#### Eager vs lazy\n\nflex computes \"live\" signals eagerly after a source has changed, and uses a\ntopological ordering to ensure that calculations are only done once and avoid\nglitches. Reagent propagates changes up the dependency chain and only\nre-calculates when dereferenced, which can avoid unnecessary work in some\ninstances but can also lead to glitches.\n\n#### Batching\n\nWhen inside of a batched transaction, flex does not compute any dependent\nsignals until the transaction has ended, even if the signal is explicitly\ndereferenced. When reagent is batching updates, it will calculate the result of\na reaction with the latest value if it is dereferenced.\n\n#### Errors\n\nIf an error occurs inside of a flex transaction, all changes are rolled back and\nno signals are updated. If you are updating a group of ratoms in reagent, if any\nerror occurs in between updates then you can end up in a state where some of the\nratoms are up to date and others are not.\n\nIf an error occurs in a flex signal, the error is propagated to consumers so\nthat it can be handled by an effect that has an `on-error` callback attached.\nReagent reactions do not propagate errors and simply fail silently, leaving your\napp in a broken state if an exception is thrown.\n\n#### Scheduling\n\nflex does all changes, computations and effects synchronously by default.\nReagent schedules some effects asynchronously using `requestAnimationFrame`.\n\n#### Nested effects\n\nEffects can be nested within each other, and when the outer effect is disposed\nit will dispose of all inner effects.\n\n#### Scope\n\nflex only handles reactive computations and has no external dependencies.\nReagent bundles together its reactive computations with additional functionality\nto build web apps in the browser, and depends on React.js for this.\n\n## Related projects\n\n### Demos \u0026 examples\n\n[helix-flex](https://github.com/rafaeldelboni/helix-flex): A simple project to setup\nand evaluate flex with [React (helix)](https://github.com/lilactown/helix).\n\n## License \u0026 Copyright\n\nCopyright 2022 Will Acton. Released under the EPL 2.0 license\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flilactown%2Fflex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flilactown%2Fflex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flilactown%2Fflex/lists"}