{"id":32181862,"url":"https://github.com/taoensso/tengen","last_synced_at":"2025-12-12T01:25:54.808Z","repository":{"id":62431967,"uuid":"70900153","full_name":"taoensso/tengen","owner":"taoensso","description":"Simple React component DSL for Clojure/Script","archived":false,"fork":false,"pushed_at":"2024-03-19T14:21:57.000Z","size":76,"stargazers_count":53,"open_issues_count":3,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-21T22:54:02.173Z","etag":null,"topics":["clojure","clojurescript","epl","om","react-native","reactjs","reagent","rum","taoensso"],"latest_commit_sha":null,"homepage":"https://www.taoensso.com/tengen","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/taoensso.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":"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},"funding":{"github":"ptaoussanis","custom":"https://www.taoensso.com/clojure"}},"created_at":"2016-10-14T10:30:42.000Z","updated_at":"2024-05-31T07:53:08.000Z","dependencies_parsed_at":"2023-01-23T03:01:01.656Z","dependency_job_id":"c9524885-f8a2-425a-a4d4-9320c401858c","html_url":"https://github.com/taoensso/tengen","commit_stats":null,"previous_names":["taoensso/tengen","ptaoussanis/tengen"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/taoensso/tengen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taoensso%2Ftengen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taoensso%2Ftengen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taoensso%2Ftengen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taoensso%2Ftengen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/taoensso","download_url":"https://codeload.github.com/taoensso/tengen/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taoensso%2Ftengen/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280348057,"owners_count":26315367,"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","status":"online","status_checked_at":"2025-10-21T02:00:06.614Z","response_time":58,"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":["clojure","clojurescript","epl","om","react-native","reactjs","reagent","rum","taoensso"],"created_at":"2025-10-21T22:54:21.689Z","updated_at":"2025-10-21T22:54:22.659Z","avatar_url":"https://github.com/taoensso.png","language":"Clojure","funding_links":["https://github.com/sponsors/ptaoussanis","https://www.taoensso.com/clojure"],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"https://www.taoensso.com\" title=\"More stuff by @ptaoussanis at www.taoensso.com\"\u003e\n\u003cimg src=\"https://www.taoensso.com/taoensso-open-source.png\" alt=\"Taoensso open-source\" width=\"350\"/\u003e\u003c/a\u003e\n\n**[CHANGELOG][]** | [API][] | current [Break Version][]:\n\n```clojure\n[com.taoensso/tengen \"1.1.0\"] ; Mature/stable (basically \"done\")\n```\n\n\u003e See [here][backers] if to help support my open-source work, thanks! - [Peter Taoussanis][Taoensso.com]\n\n# Tengen: let-based [Reagent][] components for Clojure/Script\n\n\u003e **Ten-gen** (天元) is a Japanese [Go][] term for the central, and only unique point on the Go board.\n\n[Reactjs][] has its pros and cons. Overall, it can be a good fit for web/native application development with Clojure/Script.\n\nBut while React's [lifecycle methods][] are flexible, using them correctly can be a little unintuitive.\n\nOne of the sharper edges I've found in practice, is the difficulty of **managing simple state flow** through the component lifecycle process. This can actually be harder to do in Clojure/Script than vanilla JS since Clojure intentionally discourages the kind of disposable mutable state that could be handy here.\n\nNet result: one sees a lot of weird contortions using atoms and core.async channels just to get the basic kind of data flow that you'll routinely need in a real application.\n\nAs an alternative: **Tengen** gives you a small, simple, lightweight **component constructor** that uses the unique capabilities of Lisp macros to get this:\n\n```clojure\n(def-cmptfn my-example-component\n  \"Optional docstring\"\n  [first-name last-name] ; Args given to component (will rerender on changes)\n\n  :let-mount ; Optional bindings established on each mount, available downstream\n  [norm-fn (fn [s] (str/upper-case (str s)))\n   _ (do ) ; Any side-effects on mount (fetch data from server, etc.)\n   ]\n\n  :let-render ; Optional bindings established on each render, available downstream\n  [norm-first-name (norm-fm first-name)\n   norm-last-name  (norm-fn last-name)\n\n   ;;; We also have access to two magic symbols:\n   currently-mounting? this-mounting? ; Magic `this-mounting?` binding\n   current-cmpt        this-cmpt      ; Magic `this-cmpt` binding\n  ]\n\n  :render ; Have all above bindings\n  [:div \"Full name is: \"\n   (str norm-first-name \" \" norm-last-name)]\n\n  :post-render (do) ; Optional: modify state atoms, etc. Have all above bindings.\n  :unmount     (do) ; Optional: any cleanup jobs, etc.   Have all above bindings.\n  )\n```\n\nThat is:\n\n * `:let-mount` and `:let-render` bindings automatically flow down through all later lifecycle stages.\n * Magic `this-mounting?` and `this-cmpt` bindings are automatically available through all lifecycle stages.\n\nThese two small features can help cut out a _lot_ of unnecessary complexity when writing real applications. In particular, you'll almost never need to touch or even be aware of the underlying React lifecycle methods.\n\n## Quickstart\n\nAdd the necessary dependency to your project:\n\n```clojure\nLeiningen: [com.taoensso/tengen \"1.1.0\"] ; or\ndeps.edn:   com.taoensso/tengen {:mvn/version \"1.1.0\"}\n```\n\nAnd setup your namespace imports:\n\n```clojure\n(ns my-cljs-ns\n  (:require [taoensso.tengen.reagent :as tengen :refer-macros [cmptfn def-cmptfn]]))\n```\n\nAnd you're good to go, you've already seen the entire API!\n\nCheck the `cmptfn`, `def-cmptfn` docstrings for more info.\n\n## FAQ\n\n#### Why only Reagent support?\n\nJust the most familiar with Reagent, so started there. Haven't had time yet to look at extending to other libs, but should be trivial if there's demand (please ping to let me know).\n\nI'll note that [Rum][]'s design in particular looks quite pleasant.\n\n#### How's the performance?\n\nTengen doesn't add any detectable overhead to your components, it's just a lightweight macro wrapper to Reagent's usual constructor.\n\n#### How does this affect my reactive atoms, etc.?\n\nIt doesn't, you can continue to use whatever higher-level state management strategies you prefer.\n\n#### How to access DOM nodes?\n\nAs usual for Reagent, use [ref callbacks][]:\n\n```clojure\n(def-cmptfn my-example-component [arg1 arg2]\n  [:div\n   {:ref\n    (fn [node]\n      (when node\n        ;; node is mounted in DOM\n        ))}])\n```\n\nYou can also use `(reagent.core/dom-node this-cmpt)`, etc. - but would **strongly** recommend preferring ref callbacks in general since they're a lot more reliable and React's `findDOMNode` method is expected to become deprecated soon.\n\n## Contacting me / contributions\n\nPlease use the project's [GitHub issues page][] for all questions, ideas, etc. **Pull requests welcome**. See the project's [GitHub contributors page][] for a list of contributors.\n\nOtherwise, you can reach me at [Taoensso.com][]. Happy hacking!\n\n\\- [Peter Taoussanis][Taoensso.com]\n\n## License\n\nDistributed under the [EPL v1.0][] \\(same as Clojure).  \nCopyright \u0026copy; 2016-2022 [Peter Taoussanis][Taoensso.com].\n\n\u003c!--- Standard links --\u003e\n[Taoensso.com]: https://www.taoensso.com\n[Break Version]: https://github.com/taoensso/encore/blob/master/BREAK-VERSIONING.md\n[backers]: https://taoensso.com/clojure/backers\n\n\u003c!--- Standard links (repo specific) --\u003e\n[CHANGELOG]: https://github.com/taoensso/tengen/releases\n[API]: http://taoensso.github.io/tengen/\n[GitHub issues page]: https://github.com/taoensso/tengen/issues\n[GitHub contributors page]: https://github.com/taoensso/tengen/graphs/contributors\n[EPL v1.0]: https://raw.githubusercontent.com/ptaoussanis/tengen/master/LICENSE\n[Hero]: https://raw.githubusercontent.com/ptaoussanis/tengen/master/hero.png \"Title\"\n\n\u003c!--- Unique links --\u003e\n[Go]: https://en.wikipedia.org/wiki/Go_game\n[lifecycle methods]: https://facebook.github.io/react/docs/component-specs.html\n[Reactjs]: https://facebook.github.io/react/\n[Reagent]: https://github.com/reagent-project/reagent\n[Rum]: https://github.com/tonsky/rum\n[Om]: https://github.com/omcljs/om\n[ref callbacks]: https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaoensso%2Ftengen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftaoensso%2Ftengen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaoensso%2Ftengen/lists"}