{"id":15984293,"url":"https://github.com/aappddeevv/scalajs-reaction","last_synced_at":"2025-03-15T09:31:47.500Z","repository":{"id":34227224,"uuid":"120668388","full_name":"aappddeevv/scalajs-reaction","owner":"aappddeevv","description":"scala.js react bindings in the spirit of ReasonReact","archived":false,"fork":false,"pushed_at":"2024-04-19T10:43:00.000Z","size":36756,"stargazers_count":47,"open_issues_count":25,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-02-26T23:59:00.647Z","etag":null,"topics":["microsoft","office-ui-fabric-office","react","react-libraries","reasonreact","scala","scalajs-react"],"latest_commit_sha":null,"homepage":"http://aappddeevv.github.io/scalajs-reaction","language":"Scala","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/aappddeevv.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,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2018-02-07T20:35:20.000Z","updated_at":"2024-12-24T19:06:47.000Z","dependencies_parsed_at":"2024-03-25T02:48:11.714Z","dependency_job_id":"f9fb5c51-c736-4ca6-adf4-1b6a2af1c057","html_url":"https://github.com/aappddeevv/scalajs-reaction","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aappddeevv%2Fscalajs-reaction","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aappddeevv%2Fscalajs-reaction/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aappddeevv%2Fscalajs-reaction/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aappddeevv%2Fscalajs-reaction/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aappddeevv","download_url":"https://codeload.github.com/aappddeevv/scalajs-reaction/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243713357,"owners_count":20335564,"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":["microsoft","office-ui-fabric-office","react","react-libraries","reasonreact","scala","scalajs-react"],"created_at":"2024-10-08T02:06:28.480Z","updated_at":"2025-03-15T09:31:47.023Z","avatar_url":"https://github.com/aappddeevv.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg width=\"200\" src=\"./logo.svg\"/\u003e\u003c/p\u003e\n\u003cp align=\"center\"\u003e\u003ci\u003eUse react hooks and scala.js to catch the best user experience.\u003c/i\u003e\u003c/p\u003e\n\nscalajs-reaction: ![scalajs-reaction](https://img.shields.io/maven-central/v/org.ttgoss.js/react_sjs1_3?versionPrefix=1.0.0-RC1), scala: ![scala](https://img.shields.io/maven-central/v/org.scala-lang/scala3-compiler_3?versionSuffix=3.4.0)\n\nscalajs reaction focuses on scala3 and interop with the react js world.\n\nUse react version 18+ and/or the experimental to ensure that all hooks defined in this library are included in the underlying js source. Use the latest react-native.\n\nGet started with the [docs](http://aappddeevv.github.io/scalajs-reaction)\n\nHere's how easy it is to declare a function component.\n\n```scala\nval HelloWorld: ReactFC0 = () =\u003e div(\"hello world\")\n```\n\n# What is scalajs-reaction?\n\nAn interop library with reactjs and the react ecosystem.\n\nThis library is small and focuses on simple js function components and hooks. Hooks are described on the\n[react](https://reactjs.org/docs/hooks-reference.html) page.\n\nscalajs-reaction emphasizes:\n\n- Easy to learn/use. Your component is just a standard scala.js js function.\n\n- Integration into an existing\n  project by making it easy to import/export components. You just export the function using standard scala.js.\n\n- Easy to fit into\n  existing application including those using global state-managed solutions such\n  as redux.\n\n- Build your own abstractions on top e.g. things like `slinky` or `scalajs-react`.\n\n`scalajs-reaction` allows you to build your entire interface in scalajs-reaction. As long as your front-end solution\ncan manage the model of\ncompiler scala.js's output, you should consider scalajs-reaction for your solution. By providing a thin veneer over standard scala functions and hooks, it eschews abstractions and avoids getting in your way.\n\n- [Demo (WIP)](http://aappddeevv.github.io/scalajs-reaction/demo/index.html).\n- [Live Coding](https://www.youtube.com/watch?v=7on-oT2Naco): Uses the old API but still helpful.\n\nThe react-native use-case for scala.js may be more\ncompelling than for web applications.\nSupport is provided for the experimental, reactjs concurrent API.\n\nA g8 template is available. Use `sbt new aappddeevv/scalajs-reaction-app.g8` (in transition to scala3) to create a new project.\n\n# Creating Components\n\nIt's easy to create a component and render it:\n\n```scala\n// hello world component\nval HelloWorld: ReactFC0 = () =\u003e div(\"hello world\")\n// ....\nreact_dom.createAndRenderWithId(HelloWorld, \"container\")\n```\n\nReactFC0 does not do much other than ensure that the scala function on the right\nbecomes a js function--which is all that is needed to use react. You\ncould have just declared it directly:\n\n```scala\nval HelloWorld: js.Function0[ReactNode] = _ =\u003e div(\"hello world\")\n```\n\nIf you need to pass in an argument, remember that react function components requires a single js object parameter.\n\n```scala\nobject MyComponent {\n    trait Props extends js.Object:\n        val name: String\n\n    // I use this declaration style alot.\n    val render: ReactFC[Props] = props =\u003e\n      div(\"hello \" + props.name)\n\n    // optional but helpful with browser debugging tools\n    render.displayName = \"MyComponent\"\n\n    def apply(props: Props) = createElement(render, props)\n}\n```\n\nUsing it is equally simple:\n\n```scala\nval myNodeToUse = MyComponent(new { name = \"foo\" })\n```\n\nReactFC says that the function component HelloWorld takes a single parameter, of\ntype `Props`. You do not need to use `ReactFC`, you could just use standard\nscala and standard react:\n\n```scala\nobject MyComponent {\n    trait Props ...\n\n    val render: js.Function1[Props, ReactNode] = props =\u003e div(s\"hello ${props.name}\")\n\n    def apply(props: Props) = createElement(render, props)\n}\n```\n\nor with types and extension methods:\n\n```scala\nobject MyComponent {\n  trait Props ...\n\n  // A standard scala function is a val, but its better to type it as ReactFC[Props]\n  val render: Props =\u003e ReactNode = props =\u003e div(s\"hello ${props.name}\")\n\n  // A standard def scala function, it's better to use a val\n  //def render(props: Props): ReactNode = div(s\"hello ${props.name}\")\n\n  // ReactElementTuple causes scala=\u003ejs function conversion using standard scala methods\n  def apply(props: Props): ReactElementTuple = (render, props)\n\n  // Or convert using the `.elementWith` extension method which reads nicely\n  // This is what I usually use.\n  def apply(props: Props) = render.elementWith(props)\n}\n```\n\nThat's how simple this facade is. You use the easy parts of scala.\n\nTo create a higher-order component or a \"container/pure renderer\" design, use function composition:\n\n```scala\ndef withPageLogging[P \u003c: js.Object](component: ReactFC[P]): ReactFC[P] = props =\u003e {\n  useEffectMounting(() =\u003e println(\"LOG PAGE!\"))\n  createElement(component, props) // or component.elementWith(props)\n}\n```\n\nReact needs to control when the props are applied to the rendering function, not you. A react \"element\" is really just a data structure that is a description of the element's rendering logic and props. The actual rendered element is created under react's control, not yours. There are other component specification patterns you can use as well or you can easily create your own like the above. See the docs.\n\nIf you want to ensure your component only renders when the props change, use\n`memo()`. `memo` uses shallow compare\nchecking to see if the props have changed. An extension method is available\nfor memo to apply it as syntax. You need to take into account js's notion of equality when using\nfunction components and hooks or provider your comparator, something useful when you have\nscala objects in your props.\n\nAdd state and other effects to your component using react hooks just like you normally would.\n\nThe scala.js facade implementation is ~50 lines of code and is\neasily maintained. Various conversion and extension methods are provided to make the API ergonomic.\n\nYou have many choices on how to create your components and they are all\nstraightforward. Depending on the component library you use, having choices\nhelps you find the easiest way to access the components in your application.\nThis library does not force many conventions on your code.\n\nThis facade uses standard scala.js concepts. Higher level components,\ne.g. composition of smaller components, can\nuse more idiomatic scala constructs. This library does\nnot fight scala or scala.js to make it more like js. It uses\nthe tools provided by scala and scala.js to make it easier to write react applications and control react rendering optimizations.\n\n## What is react function component?\n\nreact function components are not pure functions and can never be pure functions. Think of them more\nlike a \"context\" that is established for some part of the DOM that also returns HTML builder\ninstructions each time it is called. If you come\nfrom the java Spring world, think of it as a bean factory that knows how to emit render instructions.\nIt is better to think of react function components as an object and not as a function.\n\n# Usage\n\nThe libraries are all at the organization `org.ttgoss.js` and available on maven.\n\nInclude the library in your build:\n\n```scala\nval scalaJsReactVersion = \"latest.version\" // see the badge above\n\n// grab the the latest version or use a specific version\nlibraryDependencies ++= Seq(\n    \"org.ttgoss.js\" %%% \"react\" % scalaJsReactVersion,\n    \"org.ttgoss.js\" %%% \"vdom\" % scalaJsReactVersion,\n\n    // optionals\n    // if you need react-dom\n    \"org.ttgoss.js\" %%% \"react-dom\" % scalaJsReactVersion\n\n    // Microsoft fabric UI components, \"MS office\", css-in-\"scala\"\n    // css-in-scala can be used independently of fabric\n    \"org.ttgoss.js\" %%% \"fabric\" % scalaJsReactVersion,\n\n    // Material UI components (bootstrap is also available but limited)\n    \"org.ttgoss.js\" %%% \"mui\" % scalaJsReactVersion,\n\n    // if you integrate with redux\n    \"org.ttgoss.js\" %%% \"redux\" % scalaJsReactVersion,\n\n    // if you need prop-types--you only need these for interop scenarios\n    \"org.ttgoss.js\" %%% \"prop-types\" % scalaJsReactVersion,\n\n    // if you need react-native\n    \"org.ttgoss.js\" %%% \"native\" % scalaJsReactversion)\n  )\n  // ...\n//\n// Add import scala.language.implicitConversions to each file or\n// add scalacOptions += Seq(\"-language:_\") to your settings\n// to enable implicit conversions and all other language features\n\n// I use explicit nulls and you should to in scala.js applications at least\n// for the time being.\n  scalacOptions += Seq(\"-Yexplicit-nulls\")\n```\n\n## Include JS libraries\n\nDo not forget to include the react libraries in your execution environment. For\nreact 16+, the libraries have been split out into multiple libraries. For the\nreactjs based modules, the javascript dependencies are:\n\n- core: react\n- react-dom: react-dom\n\n```sh\nnpm i --save react\nnpm i --save react-dom\n```\n\nReact 16.8+, the one with hooks, is required. Some experimental APIs are supported\nso you may want to use the latest experimental release.\n\n## What's available\n\nThere are many bindings available as most of the focus has been on hand-crafted bindings in order\nto improve ergonomics. We'll work with ScalablyType to improve the availability of bindings, however,\nthey are quite simple to write using scalajs-reaction. All of these libraries use the group name `org.ttgoss.js`:\n\n- apollo (apollo3 only)\n- bootstrap\n- dataloader\n- data-validation (applicative data validation)\n- express\n- fabric (office-ui-fabric-react): Custom and ergonomic facade.\n- fabric-experiments\n- forms: Advanced, all-scala.js forms package.\n  - In transition so its not currently available.\n- formik\n- handlebars\n- helmet\n- jshelpers: Helpers for working with js data. Includes full js.Promise extension methods to avoid Future.\n- jss\n- lodash\n- loglevel\n- luxon (datetime library, evolved from moment)\n- msal\n- mssql\n- mui\n- native\n- pathtoregexp\n- plotlyjs\n- prop-types\n- react\n- react-content-loader\n- react-device-detect\n- react-dom\n- react-big-calendar\n- react-fast-compare\n- react-native-nativebase\n- react-native-elements\n- react-navigation\n- react-native-sideswipe\n- react-plotlyjs\n- react-redux\n- react-responsive\n- react-helmet\n- react-flexbox-grid\n- react-router-dom 6 (the v5 bindings are no longer available)\n- recoil (facebook state management)\n- use-query-params\n- use-deep-compare-effect\n- vdom\n- whydidyourender (use include/exclude regexs, see the readme in that directory)\n\nSome of the external libs have just enough scala.js bindings to write an app with\nare not fully fleshed out. In most cases, there are enhancements\nto make using the library easier.\n\nMost of the packages use a simple namespace hierarchy starting with\nthe package name versus \"ttg\" or \"scalajs-reaction\" or anything\ncomplicated. You are likely only to use one set of react libraries\nper application so you should not encounter any package namespace\ncollisions.\n\nIn many cases, the full package label has been shortened\nto make it easier to import the content. The package names\nclosely mirror the javascript libraries themselves.\n\nYou will most likely also need DOM bindings. Here's a link to the api\nfor org.scala-js scalajs-dom bindings: [![javadoc](https://javadoc.io/badge2/org.scala-js/scalajs-dom_sjs1_3/javadoc.svg)](https://javadoc.io/doc/org.scala-js/scalajs-dom_sjs1_3).\n\n# jshelpers \n\nPackage `jshelpers` is available to help with strange types. Review the docs for extra syntaxt that you can use.\n\nGenerally, if you model your data such as `js.UndefOr[A|Null]` then you will want to turn on\n`-Xexplicit-nulls` so that the `Null` type becomes explicit and not inferred.\n\n# Documentation\n\nClient:\n\n- [user](http://aappddeevv.github.io/scalajs-reaction)\n\nIntegrated API documentation:\n\n- [all basic modules](https://aappddeevv.github.io/scalajs-reaction/api/ttg/react)\n\nSometimes the documentation generation process does not work so\nif you need docs it is probably best to generate them\nlocally.\n\nGenerate integrated documents using unidoc then open the toplevel page:\n\n```sh\nget clone https://github.com/aappdddeevv/scalajs-reaction\nsbt \"docs/unidoc\"\n# linux has xdg-open to open a file from the command line\nxdg-open website/scalajs-reaction/static/api/index.html\n```\n\n# Demo\n\nYou can start the demo locally if you run `sbt npmRunDemo`. A browser page\nshould open automatically. If not, point your browser to\n[https://localhost:8080](https://localhost:8080). You can also just load the\ndemo files (after its built) into your browser but note that the icons will not\nrender correctly since they require a fetch.\n\nArgh!!! I'm having trouble with gh-pages so the demo probably does not\nwork at htis time. Run it locally after you clone the repo.\n\n# Motivation\n\nI was looking for a react facade that rethought reactive interactions. Many of\nthe existing facades are straight adaptions of the standard react library and\nmake it quite easy to program react in a scala environment.\n\nThe ReasonReact facade, using a modified OCaml syntax, keeps it quite\nsimple. This library is actually quite small and simple and relies on\nfunctions. Scala.js easily supports creating classes that map into javascript\nclasses and hence into react component classes. However, with parallel fiber\ncoming to react and other enhancements that are planned, we need to withstand the\nchange in the core react infrastructure and use an approach that is more sustainable\nin the long run. scala.js js functions are about as simple as you can get.\n\n# Suitability\n\nScala.js requires a bundling model that leverages scala.js technology\nsmartly especially when it comes to bundling/splitting and bundle size.\n\nFor mission critical apps please ensure you have explored the impact of\nusing scala.js on your application. In many cases, it may not matter.\n\nThe core scala.js infrastructure costs you about 2.5k and increases as you use\nfeatures such as immutability, the collections library or, of course, add data\nstructures to your code. Eventually, scala.js will be free fo the collections\nlibrary and other scala'ish dependencies and it's minimum file size will shrink\nfurther.\n\n# Related\n\nThere are a few [scala.js](https://www.scala-js.org/) react\nfacades/implementations available:\n\n- https://github.com/eldis/scalajs-react: Very clean class oriented react\n  implementation different jagolly's below. Class oriented but has a builder as well and includes purely\n  functional (stateless) component support as well. No macros. Allows ES\n  class-like syntax. This lib was created to get\n  around \"wrapping\" and other artifacts that the author was not fond of.\n- https://github.com/eldis/scalajs-redux: Redux facade by the same as above.\n- https://github.com/shogowada/scalajs-reactjs: More functionally oriented\n  facade. Contains redux facades and more.\n- https://github.com/japgolly/scalajs-react: The \"can't shoot yourself in the\n  foot\" implementation. Well supported and thought out but a bit more complex API\n  wise.\n- https://slinky.shadaj.me: Newcomer. Uses macros smartly. Allows you to use\n  scala.js components in js as well. Uses some macros to help with javascript\n  interop.\n- https://github.com/xored/scala-js-react: Class oriented facade. Uses macros to\n  transform xml literals so you can write xml in your code like jsx.\n- https://github.com/scalajs-react-interface/sri#sri: React-native and web. New\n  maintainers.\n- https://github.com/Ahnfelt/react4s: React wrapper. This does not just mimic\n  the standard react interface but provides its own point of view.\n  Includes an interesting CSS builder, css-in-scala.\n\nThe facades differ in their facade approach but many recreate all of the API\nparts found in reactjs. japgolly works hard to put a more safe, functional API\nin place from the outset. Some of these facades have alot of complex facade\ncomponents to help deal with the type and side-effects flexibility found in\nreact.\n\nIn theory, all of these can \"export\" a scala.js component to be used in\njavascript environments. However, various libraries that go deep into scala-land\nmeans that they are harder to use from javascript land often because they wrap\nthe javascript props and state objects in a way that makes them less usable from\nthe javascript world. Most, if not all, libraries allow you to use javascript\ndefined components fairly directly via some type of adoption or import process.\n\nLibraries you may be interested in:\n\n- [binding.scala](https://github.com/ThoughtWorksInc/Binding.scala): reactive UI\n  framework. It uses a new binding framework for scala. Works on jvm and js. The\n  binding framework is at a individual element level like mobx. You can use xml\n  syntax as well. The binding approach is called \"precise\" binding.\n- [diode](https://github.com/suzaku-io/diode): redux replacement.\n- [laminar](https://github.com/raquo/laminar): a reactive web framework.\n- [levsha](https://github.com/fomkin/levsha): Fast pure scala.js virtual dom.\n- [pine](https://github.com/sparsetech/pine): XML/HTML builder.\n- [scalacss](https://github.com/japgolly/scalacss): A solid css-in-scala solution.\n- [scala-dom-types](https://github.com/raquo/scala-dom-types): for dom attributes.\n- [scala-tags](https://github.com/lihaoyi/scalatags): XML/HTML builder.\n- [outwatch](https://github.com/OutWatch/outwatch/): reactive UI framework.\n- [udash](https://udash.io/) is another reactive framework that is not\n  react based, but reactive.\n- [udash-css](https://udash.io): A css-in-scala framework.\n\n# License\n\nMIT license. [![GitHub license](https://img.shields.io/badge/license-MIT-lightgrey.svg?maxAge=2592000)](https://raw.githubusercontent.com/aappddeevv/scalajs-reaction/master/LICENSE)\n\nCopyright 2018 The Trapelo Group LLC.\n\nThe logo was created partially from content provided by [Scott De\nJonge](https://www.flaticon.com/authors/scott-de-jonge) under CC3.0.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faappddeevv%2Fscalajs-reaction","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faappddeevv%2Fscalajs-reaction","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faappddeevv%2Fscalajs-reaction/lists"}