helix

jeaye 2023-03-28T19:36:02.986339Z

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. 🙂

hifumi123 2023-03-28T19:40:52.383939Z

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

jeaye 2023-03-28T21:13:39.441259Z

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.

jeaye 2023-03-28T21:16:05.174229Z

Hm, based on the doc, it will.

lilactown 2023-03-28T21:22:04.087549Z

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

lilactown 2023-03-28T21:26:52.369419Z

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 explicitly

jeaye 2023-03-28T21:28:46.514199Z

Interesting. 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?

lilactown 2023-03-28T21:29:19.090379Z

that's right

jeaye 2023-03-28T21:29:43.993259Z

Gotcha. This is great information and I appreciate you taking the time to write it out. 🙂

hifumi123 2023-03-28T21:35:44.968639Z

Although nobody asked, I’m also dealing with a re-frame/reagent app, slowly migrating to Helix 😄

hifumi123 2023-03-28T21:36:25.210109Z

@jeaye there is a neat trick you can do if you want to use basic destructuring syntax with js objects

hifumi123 2023-03-28T21:36:50.116669Z

Check out the reify example in https://stackoverflow.com/a/49848352

hifumi123 2023-03-28T21:37:15.638919Z

Only downside is that nested map destructuring won’t work, but that often produces unreadable syntax anyway

jeaye 2023-03-28T21:38:09.988289Z

Do you see measurable perf wins after converting views from reagent?

hifumi123 2023-03-28T21:39:26.074689Z

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

hifumi123 2023-03-28T21:41:09.222699Z

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

hifumi123 2023-03-28T21:44:45.411579Z

Major caveat: these are NOT real-world benchmarks. The version of reagent and helix used is also very out-of-date.

hifumi123 2023-03-28T21:45:39.964199Z

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

hifumi123 2023-03-28T21:46:24.280519Z

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.

jeaye 2023-03-28T21:58:08.496049Z

Thanks!

👍 1