Skip to content

Instantly share code, notes, and snippets.

@holyjak
Last active July 11, 2022 06:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save holyjak/ff152bb5c0edaf9575e0ba2b051e8a8a to your computer and use it in GitHub Desktop.
Save holyjak/ff152bb5c0edaf9575e0ba2b051e8a8a to your computer and use it in GitHub Desktop.
TMP: Example of using forwardRef and passing the result to a HoC JS component
;; Example of using forwardRef and passing the result to a HoC JS component
;; ...
(defn shallow-js->clj [^js obj]
(persistent!
(reduce (fn [r k] (assoc! r (keyword k) (gobj/get obj k)))
(transient {}) (js-keys obj))))
;; My Fulcro component that needs a DOMElement ref and is passed to the JS HoC
(defsc MyDropdownList [this {:dropdown/keys [text] :as props}] ; Fulcro props
{:ident (fn [] [:component/id :MyDropdownList])
:query [:dropdown/text]
:initial-state {:dropdown/text "Select"}}
(let [{:keys [onMenuOpen isMenuOpened forwardedRef]} props] ; JS props from the parent component / call site
(dom/div {:ref forwardedRef
:onClick onMenuOpen
:title (str "Props: " (pr-str props))}
text " " (if isMenuOpened "v" ">"))))
;; Raw JS functional component adapting between the calling JS world and the child Fulcro world - magic happens here
;; I could make a fn/macro that produces this fn given the target Fulcro component class
(defn MyDropdownListAdapter [^js js-props]
(let [fulcroProps (hooks/use-component app/app MyDropdownList nil)]
(comp/with-parent-context ; this is necessary since we're are rendered by JS land
(.-fulcroParent js-props)
((comp/factory MyDropdownList)
(-> js-props shallow-js->clj (dissoc :fulcroParent) (merge fulcroProps))))))
;; Wrap the component with forwardRef to get access to the `ref` passed in by the parent JS HoC
(def MyDropdownListAdapterWithRef
(react/forwardRef
(fn [js-props ref]
(dom/create-element MyDropdownListAdapter
(doto (gobj/clone js-props) (gobj/set "forwardedRef" ref)))))) ; clone necessary b/c props not extensible
;; My parent Fulcro component that renders the JS HoC and passes it the child component
(defsc MyDropdownListWrapper [this _]
{:ident (fn [] [:component/id :MyDropdownList])
:initial-state {}}
;; NOTE: `ComponentWithDropdown` is a pure JS higher-order component
(dom/create-element ComponentWithDropdown ; not interop/react-factory b/c I don't want to clj->js componentProps recursively
#js {:options #js [#js {:label "One" :value 1 :onClick #(m/set-value! this :ui/selected 1)}
#js {:label "Two" :value 2 :onClick #(m/set-value! this :ui/selected 2)}]
:Component MyDropdownListAdapterWithRef
:alignMenuTo= "left"
:componentProps #js {:testProp {:clj-map? true} :fulcroParent this}}))
(defsc Root [this _]
{:use-hooks? true}
((comp/factory MyDropdownListWrapper) {}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment