Fork me on GitHub
#reagent
<
2021-01-03
>
Justin Hong02:01:57

Hi! Just joined the Slack and this is my first post here 🙂. Had a docs suggestion for the https://cljdoc.org/d/reagent/reagent/1.0.0/doc/tutorials/when-do-components-update- tutorial’s https://cljdoc.org/d/reagent/reagent/1.0.0/doc/tutorials/when-do-components-update-#changed section: perhaps removing most of it and just adding a note that before Reagent 0.6.0 ratoms used identical? but as of 0.6.0 they use =? The way it is right now, with most of the discussion on identical? vs. = and how ratoms use the former and then a small Update section at the end saying that’s actually not the case anymore, seems off. I can put up a PR but wanted to hear y'all's thoughts first.

👋 1
Rebecca Bruehlman19:01:53

I have a modal I want to clear if the user clicks outside of it. with-let seemed promising/cleaner than accessing lifecycle methods, but I need access to the current component to set up the event handler, and it didn’t much appreciate my using rdom/dom-node . So, lifecycle methods it was. However, while I’m able to set up the event handler, it doesn’t get removed upon unmount. I assume this is because partial doesn’t return the same function each time (really, I’d get the same result with an anonymous function). However, I’m at a loss of how I would pass the component into my function otherwise. React seems to sidestep this problem by including handle-outside-click as a function to the component itself and then referencing JavaScript’s ever-nebulous this, but I’m not sure what the cljs/Reagent equivalent is?

defn handle-outside-click [this event]
  (when (and this (not (.contains this (.-target event))))
    (rf/dispatch [::modal-events/toggle-camera-modal false])))

(defn camera-modal [state]
  (r/create-class
   {:display-name "camera-modal"

    :component-did-mount
    (fn [this]
      (.addEventListener js/document "mousedown"
                         (partial handle-outside-click (rdom/dom-node this))))

    :component-will-unmount
    (fn [this]
      (.removeEventListener js/document "mousedown"
                            (partial handle-outside-click (rdom/dom-node this))))

    :reagent-render
    (fn []
      (let [modal-status @(rf/subscribe [::modal-subs/camera-modal])
            visible-photo @(rf/subscribe [::photo-subs/photo-visibility])]

        [:div {:id "camera-modal"
               :class "modal"
               :style (merge
                       {:background-color "#D3D3D3"
                        :border-radius "15px"
                        :margin-top "30px"
                        :display (if modal-status "block" "none")}
                       @state)
               :key "camera-modal"}
         (if visible-photo
           [photo-section]
           [streaming-section state])]))}))

p-himik19:01:49

You almost never really need to use react.dom/dom-node because there are other, often more reliable, ways to achieve the same. In fact, findDOMNode is deprecated in ReactDOM in strict mode. To get the DOM node, just use React refs via the :ref attribute. To handle clicking outside of something, the most common approach is to create a transparent backdrop element and handle its :on-click event.

p-himik19:01:21

In the example above, the event listener is not removed because two calls to (partial ...) always return different objects.

p-himik19:01:22

To get some inspiration, you can check out the source code of re-com. Check out its demo and notice the "add backdrop" checkbox on the right-hand side: https://re-com.day8.com.au/#/popovers

Rebecca Bruehlman19:01:16

Ah, cool--thanks, this is helpful! Good to know on the transparent backdrop element bit--I’ll try that. Sounds simpler

p-himik19:01:10

A few unrelated things: - When providing pixel sizes in :style, you can just use a number instead of a string with px in it. But you have to use strings if you need to use other units - You can use keywords instead of strings for pretty much everything in :style - it's especially relevant to CSS keywords like block and none - You can also use keywords and even collections when specifying :class in Reagent. Makes it possible to write things like {:class [:menu-item (when active? :active)]}. Pretty sure you can use a keyword for :id as well - I don't think you have to specify :key if you provide it with only a static value. But that depends on the usage of camera-modal

Rebecca Bruehlman19:01:31

Really appreciate the pointers--learning cljs as a hobby, rather than work, so feedback is hard to come by. I’ll make those changes

👍 3