reagent 2023-03-06

Hello ๐Ÿ™‚ In new versions of reagent, I get a warning that reagent.dom/dom-node is deprecated, however the documentation does not say what to replace it with. My use-case: I have a very simple component thatโ€™s a code block <code></code>. On mount of this component, I want to call highlight JSโ€™ highlightElement. I have code which looks like this:

(defn highlight-element
  [el]
  (.highlightElement hljs (reagent.dom/dom-node el)))

(defn code-block
  ([s lang]
   (reagent/create-class
    {:reagent-render       (fn [s] [:code (when lang {:class lang}) s])
     :component-did-mount  highlight-element
     :component-did-update highlight-element})))
Can someone please help me figure this out?

You should replace that function with React refs.

Note also that :component-did-mount receives not el but this - an instance of the component itself and not its corresponding DOM node (which might not even exist).

oh boy

Thanks for the info and quick reply! On to learning about React refs then.

In this case, it'll be something as simple as:

;; The exact `:require` vector might be different, depends on your build tool.
;; I'm using only shadow-cljs - this works there just fine.
(require '["react" :as react]
         '[reagent.core :as r])

(defn highlight-element
  [el]
  (.highlightElement hljs el))

(defn code-block
  ;; Note that I moved `lang` to the render fn since otherwise changing the arg would not cause a re-render.
  [_ _]
  (let [ref (react/createRef)]
    (r/create-class
      {:reagent-render       (fn [s lang]
                               [:code {:ref   ref
                                       ;; No need for `when` here, even if `lang` is `nil`.
                                       :class lang}
                                s])
       :component-did-mount  (fn [_this]
                               (highlight-element (.-current ref)))
       :component-did-update (fn [_this _old-argv _old-state _snapshot]
                               (highlight-element (.-current ref)))})))

๐Ÿ‘ 1

Is there a reason why I should not do this?

(defn highlight-element
  [el]
  (.highlightElement hljs el))

(defn code-block
  ([s]
   (code-block s nil))
  ([s lang]
   [:code
    {:ref   (fn [el] (when el (highlight-element el)))
     :class lang}
    s]))

Ah, I guess the ref callback is called twice, so sometimes el can be nil, which causes the call to highlight JS to fail. As far as I understand, I do not need the :component-* callbacks anymore.

Looks like itโ€™s working like a charm on my end. ๐Ÿ™‚ I only removed code ๐Ÿฅณ

Ref fn is called when the component is mounted or unmounted, which might not happen always when s changes. So it is possible the highlights aren't always updated when the code changes.

One option would be to use useEffect hook to trigger the call when ref or code changes:

(let [ref (react/useRef)]
  (react/useEffect
      (fn []
          (when (.-current ref)
             (.highlightElement (.-current ref)))
         js/undefined)
       #js [(.-current ref) s])
   [:code ...])
Something like this.

Or useEffect without the dependencies would run after every render similar to componentDidMount + componentDidUpdate