Hello! I have a reagent application which I'm trying to turn into a vanilla JS library. Extracting the model portions and providing JS entrypoints for them, with judicious js->clj usage, does the trick. But I was surprised to find that reagent components can't be used within normal JS React apps. Someone recommended Helix.
I'm curious, and I didn't see it in the docs, so I'll ask a few things here:
1. Can Helix and Reagent coexist so I don't need to rewrite every Reagent component?
2. Can I avoid rewriting Reagent components I want to use from JS by wrapping them in a Helix component which uses Reagent behind the scenes? (accepting any perf costs)
3. Perhaps on top of all of that, what's the recommended approach going forward?
I appreciate the support. đ
1. of course; the docs have a dedicated section on this https://cljdoc.org/d/lilactown/helix/0.1.10/doc/integrating-with-other-libraries 2. this is ultimately going to call r/as-element in helix which then creates another react element, I wouldn't recommend doing this
Thanks for the response! Missed that doc, when going through the docs linked on the README. For the second point, you're saying that you don't recommend it because of the inefficiencies, which I 100% get. But would this work reliably? I'm interested first in getting the lib working, then making it fast.
Hm, based on the doc, it will.
our production app is a re-frame/reagent app that we have been slowly migrating to helix the last 3 years. we use helix and reagent together in almost all of our views
using components written with CLJS in JS can be tricky, since we prefer to use our immutable maps/sets/vectors/seqs instead of mutable JS data. helix by default accepts a JS object as props, so if you do something like
(defnc ^:export MyComponent
[{:keys [foo barBaz children]}]
,,,)
then in JS you can do
<MyComponent foo="bar" barBaz="qux">
<div>child</div>
<div>child2</div>
</MyComponent>
however, data that you pass to props will not be converted to CLJS data, so you'll need to call js->clj on props that you pass objects and arrays to get out maps and vectors, or your code will need to operate on objects and arrays explicitlyInteresting. But for {:keys []} destructuring to work, props has to be a cljs map, right? So Helix converts the top-level props into a map, but not recursively?
that's right
Gotcha. This is great information and I appreciate you taking the time to write it out. đ
Although nobody asked, Iâm also dealing with a re-frame/reagent app, slowly migrating to Helix đ
@jeaye there is a neat trick you can do if you want to use basic destructuring syntax with js objects
Check out the reify example in https://stackoverflow.com/a/49848352
Only downside is that nested map destructuring wonât work, but that often produces unreadable syntax anyway
Do you see measurable perf wins after converting views from reagent?
Material UI feels a lot snappier on my older devices when I use Helix instead of Reagent, but itâs an unfair comparison since in reagent I was using a wrapper library that did things like automatically convert CLJS maps to JS objects, convert cases, etc., whereas in Helix I am using the raw components directly
if you ever find yourself in a case where you need to re-render frequently, then helix definitely gives you measurable speed improvements â I think itâs hard to benchmark perf in general because benchmarks are often detached from âreal worldâ use cases
Source: https://krausest.github.io/js-framework-benchmark/2023/table_chrome_111.0.5563.64.html
Major caveat: these are NOT real-world benchmarks. The version of reagent and helix used is also very out-of-date.
there is a very small chances your app will be doing things like creating 10,000 rows then appending an additional 1,000 rows to it; thatâs why I think these are not âreal worldâ benchmarks
e.g. if you find yourself needing to render a table with 10,000 rows, then you will very likely want to use react-virtualized anyway, regardless of whether you use pure react or a wrapper library, which makes the âcreate many rowsâ benchmark kind of pointless.
Thanks!