Fork me on GitHub
#reagent
<
2021-07-21
>
Mitul Shah15:07:44

Hi! How do you write compound components in Reagent? I thought it would be [:> Root AlertDialog.. etc] but no luck

p-himik15:07:30

AlertDialog.Root is just a JS field access. A proper way would be (.-Root AlertDialog).

Mitul Shah15:07:31

damn, always the little things :face_palm: thank you so much!

👍 2
athomasoriginal15:07:44

There are a few ways fo achieve this depending on what you’re looking for:

[:<>
  [child ...]
  [child ...]
  [child ...]]
but then if you wanted your component to just accept children without the need to use a fragment:
(defn parent-component 
   [props & children]
   (into [:div props] children))
  
[parent-component
  {...} ;; props
  [child]
  [child]
  [child]]
Note that I added props as the first arg of parent-component : this is a style preference I have when writing components. You can omit that if you like.

Mitul Shah16:07:21

thanks thomas! but not sure if this was what i needed. turns out i just had to write (.-Root AlertDialog).

alexdavis19:07:01

Anyone know what translating this into cljs looks like?

<CountdownCircleTimer>
    {({ remainingTime, animatedColor }) => (
      <Animated.Text style={{ color: animatedColor }}>
        {remainingTime}
      </Animated.Text>
    )}
  </CountdownCircleTimer>
I think it should be
(def text (r/adapt-react-class (.-Text ReactNative)))
(def countdown (r/adapt-react-class CountdownCircleTimer))
[countdown
      (fn [^js props]
        (let [remaining-time (j/get props :remainingTime)
              color (j/get props :animatedColor)]
          (r/reactify-component
           [text
            {:style {:color color}}
            remaining-time])))]
but that doesn’t work, I’ve tried many combinations of things that I think should work but nothing does and I’m not getting any useful errors back, possibly because I’m in react-native land and the quality of errors tends to go downhill a bit there

alexdavis19:07:38

Its expecting ‘children’ to be a function that returns a Text react component, but I’m pretty sure thats what I’m doing 🤷

p-himik19:07:59

Try replacing r/reactify-component with r/as-element.

alexdavis19:07:06

That didn’t work either

alexdavis19:07:13

I’m thinking its because of whatever reagent generates, its not compatible for whatever reason

p-himik19:07:35

Also, your JSX example uses Animated.Text but the CLJS code uses ReactNative.Text. Maybe it's important, dunno.

p-himik19:07:47

If you get any errors - do post them.

alexdavis20:07:18

Ok I figured out I can run react native stuff in web mode and then get errors in the console. So with my first example (reactify-component)

Functions are not valid as a React child.
With as-element... it worked.. now I feel embarrassed, I was sure I tried that facepalm

alexdavis20:07:12

Out of interest, is there a better way to write it? It seems I'm going from react component (.-Text animated) to reagent component with adapt-react-class to react again

p-himik20:07:08

Depends on metrics you use to decide if something is better or not. That above is pretty much idiomatic Reagent code, although I'd probably use direct JS interop nowadays instead of j/get, especially given that you already use ^js. Another way would be to create a React element yourself - then you would not need to use r/as-element and (def text ...).

alexdavis20:07:05

Yes bad habit of mine to use j/get, ok I will look into how to create React elements manually. Thanks for the help btw, much appreciated

mauricio.szabo22:07:43

Hi there! I'm doing a quite complicated code that allows users to define, with hiccup, their own reagent views. The problem is that I need to catch errors, any anything I'm doing is still leaking errors to console, etc... Do anybody have any tips on doing this? I'm quite on a lost here...

mauricio.szabo22:07:42

So far, I tried error-boundary but it fails if the hiccup itself is invalid for example, if a [element {params...} throws an error

mauricio.szabo22:07:03

I also tried render-to-string around a try-catch, but it also fails

mauricio.szabo22:07:23

A little bit more info on this: Seems that if I use:

(let [old reagent.impl.component/wrap-render]
  (with-redefs [reagent.impl.component/wrap-render (fn [ & args]
                                                     (prn :args args)
                                                     (try
                                                       (apply old args)
                                                       (catch :default e
                                                         (prn :error e))))]
I can catch the error. Is far from ideal.... but it works. Any tips on making this better? 😄

mauricio.szabo03:07:58

Nevermind.... on a "real world scenario" it also doesn't work (I believe because it's async). I'm quite on a lost here on what to do... I'll try to get a minimal example and post here, and see what can be done

mauricio.szabo19:07:32

Ok, after lots of trying and poking on the internals, I can somehow make a "try-catch" for Reagent renderers that works for my case - but it "monkey-patches" wrap-render in some way. Not sure if there's a better way, but these are the lines I changed: https://gitlab.com/clj-editors/repl-tooling/-/merge_requests/3/diffs#diff-content-5c606df7924556558908352ff1671bf3de7b9fcc. I hope I can somehow find a better way to solve this issue, because I don't think it's a good solution, really, to the problem I have to solve 😅

lilactown23:07:57

an error-boundary should work as long as there's a component between what throws the error and the boundary

lilactown23:07:03

i.e.:

;; doesn't work
(defn my-component
  []
  [error-boundary (throw (ex-info "Oh no!" {}))])

(defn root
  []
  [my-component])

;; does work
(defn my-component
  []
  (throw (ex-info "Oh no!" {})))

(defn root
  []
  [error-boundary [my-component]])

mauricio.szabo03:07:58

Nevermind.... on a "real world scenario" it also doesn't work (I believe because it's async). I'm quite on a lost here on what to do... I'll try to get a minimal example and post here, and see what can be done