Last active
July 11, 2022 06:26
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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