A minimalistic ClojureScript interface to React.js



How can I pass static property to a Reagent component. I'm trying to reproduce persistent layout from this example:

const Home = ({ user }) => {
  return (
      <p>Hello {}, welcome to your first Inertia app!</p>

Home.layout = page => <Layout children={page} title="Welcome" />

simongray 2021-04-26T12:42:38.179900Z

@admin055 I’m not totally up-to-speed on modern JS and terminology. What is a static property?


This part

simongray 2021-04-26T12:45:01.181800Z

So Home is a function and Home.layout is another function?



simongray 2021-04-26T12:45:29.182200Z

What’s the point??

simongray 2021-04-26T12:46:46.183600Z

AFAIK you can’t add fields to Clojure Fns which is what reagent uses as functions, but why not simply have two separate functions? Why does it need to be embedded inside a JS object?


Inertia.js use it for persistent layouts and I'm trying to reproduce with Reagent.

simongray 2021-04-26T12:51:47.187100Z

I’m not even sure what a persistent layout even is (I’m not familiar with intertia.js), but I have a hard time seeing why it needs to be structured like that to work.

jkxyz 2021-04-26T12:52:29.187800Z

This is useful in JSX when you want to accept a generic component as children, which should implement some interface that can be accessed by getting the component type within the parent and calling its static methods

jkxyz 2021-04-26T12:53:58.189200Z

If it’s for interop with a JS library then I think that it might work like so (def MyComponent (reagent.core/reactify-component my-reagent-component)) (set! (.-layout MyComponent) (fn {} ,,,))

simongray 2021-04-26T12:54:57.189500Z

^^ makes sense


Thanks @josh604 for your suggestion, I try.

jkxyz 2021-04-26T13:07:21.195600Z

Since MyComponent is now a plain React component, you would have to use the form [:> MyComponent] . You might be able to achieve the same thing in a form-3 Reagent component using reagent.core/create-class and calling set! as above on the class object, inside of the form-3 function


Can someone help me with what I'm doign wrong here?

(defn test-scroll []
  (let [scroll-position (reagent.core/atom 0)]
     [:textarea.text-editor {:on-scroll (fn [^js e]
                                            (js/console.log (.. e -target -scrollTop))
                                            (reset! scroll-position (.. e -target -scrollTop)))}]
     [:div (str "Scroll pos: " @scroll-position)]]))
I just want to scroll the textarea and update scroll-position when it scrolls. When I scroll the editor, the console updates with the scrollTop value. But I think I'm doing something wrong with the atom. It always shows 0 in the test div at the end. When I scroll the console shows this:

simongray 2021-04-27T07:32:08.199Z

@qmstuart If you have a stateful component it needs to be either form-2 or form-3. with-let just allows you to make a form-2 component while skipping the inner render function, saving you a few characters and a level of indentation. I recommend reading this:

p-himik 2021-04-27T10:02:36.199400Z

with-let works like a form-2 component in most of the cases, but it's not entirely like it. It's a form-1 component with cache. And you can explicitly make it work differently.


yeah, i had read about form-1, form-2 then I started using re-frame and it doesn't need to the form-1, form-2 stuff and for some reason I just completely forgot that local state still needs a form-2. It just completely went out of my head 😞 I'm still learning this stuff and am definitely still in the idiot stage 😄


thanks guys


Would you say getting the scroll position of a textbox and scrolling a second text box to keep them in sync is a good use for component state ?


or would it be better as a re-frame reg-fx ?


feels like local state makes more sense.

p-himik 2021-04-27T10:08:00.200600Z

I agree.

p-himik 2021-04-27T10:10:07.200800Z

With an atom, you might also notice lags in scroll position synchronization. If that's an issue, you might want to combine two text boxes in a single component and sync their scrolling position via regular imperative JS.


Yeah, that's a good point. I do actually see a tiny lag... This seems to work ok though:

:on-scroll (fn [^js e]
              (let [scroll-pos (.. e -target -scrollTop)]
                  (-> js/document
                      (.getElementById "lineNos")
                      (set! scroll-pos))))
Is that reasonable ?


I've put both textboxes in the same component / function

p-himik 2021-04-27T10:13:38.201400Z

(.getElementById "lineNos") - not a great thing, impossible to reuse. Use React refs instead.

p-himik 2021-04-27T10:14:26.201700Z

Otherwise, seems reasonable, yeah.


you mean `


p-himik 2021-04-27T10:15:36.202100Z

Nope. I mean this:


thanks! I'll have a read

p-himik 2021-04-27T10:17:32.202500Z

(reagent/with-let [ref2 (reagent/atom nil)]
    [:textarea {:on-scroll (fn [^js e] (when-some [node2 @ref2] ...))}]
    [:textarea {:ref #(reset! ref2 %)}]])

p-himik 2021-04-26T22:06:55.197900Z

Replace let with reagent.core/with-let.

p-himik 2021-04-26T22:07:10.198100Z

Otherwise, the ratom gets reset on each render.


thank you! that works 😄


Do I need this because I'm doing (reset!), if I was using (swap!) would I be ok with just let ?

p-himik 2021-04-26T22:18:14.198700Z

Any change to a ratom that's deref'ed inside a view will cause that view to be re-rendered.