react

"mulling over state management stuff"
martinklepsch 2021-04-10T00:07:46.059500Z

@lilactown I’m curious - would this type of stuff be easier with helix? This is kind of a toy project so I have freedom to just try other stuff and maybe it’d be a good excuse to take helix for a spin :)

lilactown 2021-04-10T00:53:17.060Z

helix does provide slightly easier support for using 3rd party JS

lilactown 2021-04-10T00:56:37.062400Z

helix treats all components the same when creating elements:

(defn styled [type m]
  (.styled stitches (name type) (clj->js m)))

(def blue-button (styled :button {:background "blue"}))

;; render it like any other component
($ blue-button {:id "special-blue-button"} "Click me!")

lilactown 2021-04-10T00:57:59.063900Z

what it does not do is transform props into DOM-friendly names or anything. so you'll want to use camel-case event handlers and other such things:

($ blue-button {:onClick #(println "You clicked me!")} "Click me!")

lilactown 2021-04-10T01:00:33.065800Z

I'm going to provide a helix.dom/$d macro which does do that transformation for you for any component you give it, just haven't gotten around to it. maybe i'll make that my saturday morning project 🙂

martinklepsch 2021-04-10T10:54:28.067600Z

@lilactown Is there any fundamental issue that requires these helpers? It would be much nicer (IMHO 😅) to just be able to call (blue-button ,,,) but I’m realizing that helix’s $ and rum’s adapt-class both don’t seem to aim for that?

lilactown 2021-04-10T16:20:18.073100Z

two fundamental things IME. some of this you may know but I'll say it for good measure. 1. You don't want to call components directly as functions. Instead, we create elements which describe how to render the component. This lazy evaluation allows React to understand the boundary to encapsulate your component instance's state and lifecycle, and perform tricks like error boundaries, suspending/resuming rendering and time slicing. 2. You could create elements via higher-order-functions (as Rum and Fulcro does with their components), however this prevents us from doing compile-time analysis and optimizations.

2021-04-12T09:50:28.100700Z

That should go to a blog 🙂

lilactown 2021-04-10T16:23:48.076200Z

in helix's case, helix creates React components. They accept JS objects as props and return React elements. so you need to convert the props map you pass in at element creation to a JS object (`$` does this at compile time), and then this gets reconverted to a map-like thing when you're in the body of the component (`defnc` does this at runtime, but very cheaply using cljs-bean)

lilactown 2021-04-10T16:27:11.079300Z

Rum and other libraries navigate this conversion and reconversion problem not through compile-time tricks, but by passing in all of your CLJS data into one special prop that then your component plucks. so it looks more like this:

(react/createElement my-rum-component #js {:rum-props ,,,})
and then the rum component plucks its props out of that.

lilactown 2021-04-10T16:28:39.080300Z

this trick doesn't work on 3rd party React components, though, only those created by Rum. so you have to fall back to helpers that will convert your props map to a JS object in that case, which adapt-class does

lilactown 2021-04-10T16:28:54.080600Z

adapt-class, like $ tries to do all of its work at compile time in order to avoid creating a bunch of maps, parsing them and then throwing them away during render

lilactown 2021-04-10T16:30:15.081700Z

if you do want to have a blue-button that you can call like a function, helix does provide a tool for that: "spread props" a la JSX

lilactown 2021-04-10T16:30:57.082300Z

(defn styled [type m]
  (.styled stitches (name type) (clj->js m)))

(def blue-button* (styled :button {:background "blue"}))

(defn blue-button
  [props & children]
  ($ {:& props} children))

lilactown 2021-04-10T16:32:05.083700Z

the special :& keyword passed into the props map will cause $ to emit code to convert props to a JS object at compile time and merge it in with any static props you've written. in this way, you can have your compile-time cake and eat some of it at runtime, too 🙂 at a glance, I didn't see this capability in rum/daiquiri

lilactown 2021-04-10T16:34:43.085200Z

this isn't the default way of using helix because I like having the static props compilation whenever possible. helix also provides the ability to opt in to creating components as factory functions similar to rum and fulcro, but I don't know how much I want to support that going forward tbh