reactR in pinkgorilla
awb99 opened this issue · comments
I am working on pink-gorilla [https://github.com/pink-gorilla/gorilla-notebook] - a web based notebook to do data-science with clojure. The frontend is written in Reagent (which uses React).
We have a little bit of R integration already in gg4clj [https://github.com/pink-gorilla/gg4clj].
In theory I don't think it should be difficult to make available reagent-components that are created by R.
I think the critical issue that has to be solved is the dependency management.
I have to say I am not an R expert at all. However, I looked into some R html widgets and saw that
there is some kind of dependency managment built into them.
We currently use requirejs where we do globally a dependency configuration and then modules
that are loaded essentially have to return a module that defines the functions it wants to export. Example: https://github.com/pink-gorilla/gorilla-renderable/blob/master/src/pinkgorilla/ui/module_test.clj
Could you tell me what kind of format you would spit-out from reactR if I would call your module?
I would guess it will be a javascript function as a string.
What I am interested in is if you automatically compile react into that javascript or if there
are options to keep this separate?
My idea is that all those htmlWidgets from R that are complex and not easily replicated in Clojure
should be available to be used from Clojure.
Once one is so far to do widgets that do interaction on the front-end I feel react is the only way
to get this done. So I figured why not start with React at the outset.
Thanks!
Hi, do I understand correctly that you are interested in using R htmlwidgets from Clojure? Regardless, I'm happy to share what I know about the relationship between htmlwidgets, JS, Clojure/Script/Reagent, and React.
htmlwidgets do have at least two major conventions for expressing JavaScript dependencies. The first is by including "HTML dependencies" in the list of tags returned by a widget's constructor function. Widget constructor functions (or "UI functions") are analogous to ClojureScript functions that return Hiccup, except for htmlwidgets they are R and execute on the server-side. An html dependency is a special kind of tag that is interpreted as an instruction to attach a particular script to the page when it is encountered. In this way, widgets/UI functions can be distributed as R functions, and they attach their JS dependencies dynamically the first time they are used. Here's an example: https://github.com/react-R/colorpicker-example/blob/master/R/colorpicker.R#L80-L86
The second way is declaratively, via yaml file: https://github.com/rstudio/colourpicker/blob/master/inst/htmlwidgets/colourWidget.yaml This yam file is interpreted by htmlwidgets library code when the widget is first declared. It also ultimately becomes html dependency tags, but they're created for you by htmlwidgets machinery.
So, htmlwidgets that add dependencies dynamically via html dependencies have statically-unknowable dependencies. If the widget has a yaml file though, its dependencies can be known without constructing it.
What reactR does, is make React components accessible from R as if they were something like normal Shiny/R "UI functions" - functions that you call that return UI elements, and everything bottoms out ultimately to HTML5 tags. In this way, reactR affords something to R like what Hiccup/Reagent affords cljs.
Concretely, reactR is a JS library that one depends on in their input/htmlwidget. The JS code interfaces the Shiny/htmlwidget APIs with React's rendering lifecycle. When a user uses reactR to build a compound React component in R, what they're really doing is building a data structure that will be sent to the browser in a format like Hiccup and interpreted there.
The goal with reactR was to empower R users to wrap extant React libraries (or new ones) with enough R so that they could be easily used from R. The role of R is then limited to composition of these React components, and to the massage into R formats any data they might send to R from the browser.
I don't know what R html widgets you saw and that looked compelling, but they are likely not themselves implemented using reactR, and so do not contain any React components that you could re-use. They probably wrap various JS libraries that you could also yourself wrap, with some combination of clj/cljs.
The other aspect of this is that conversion-to-R-data-formats part I mentioned. htmlwidget frontend code is usually pretty tightly coupled to the presumption of an R backend, and I don't think it's generally practical to drive them from anything but R. That said, there are various R-in-Java projects that might be mature enough to prove me wrong.
I don't think I have a great idea of what exactly you're asking, so I suspect you may still have questions. If you do, please don't hesitate to ask them, I'm happy to elaborate further on all of this.
Wow! Thank you so much for your explanations! That was very helpful! I will not be using reactR then, using react from clojurescript which already has react does not really help.
My idea was that since R already has so many wrappers to Javascript, I could use this wrappers feom clojure. Essentially all the functions implement render (element, data). So if I can read the source code for a list of r html widgets I could render them in my notebook similar to R would. This saves me from writing 50 wrapper classes that are defined in R and allows R users to jse the same functions in pinkgorilla notebook.
https://github.com/daattali/colourpicker/blob/master/inst/htmlwidgets/colourWidget.js
It seems that widgets call HTMLWidgets.widget to implement the widget api. So in a sense when widgets are created I have to hook this HTMLWidgets. Widget to a function that I provide and then I would have to hook R to forward the data that should be presented to my page.
This is for sure not complicated in terms of number of lines of code to write, but complicated to understand the way the system bootstraps itself.
Again thanks for your help!
Going to close. Please reopen if you would like to continue to discuss. Thanks!
Thanks a lot!