Fork me on GitHub
Roman Liutikov17:09:05

Could be interesting for React wrappers authors: A common approach in ClojureScript React wrappers for passing Clojure props map into a component is to wrap it into actual JS object of props e.g. #js {:props {:x 1}}. While Reagent is doing this because they want to support positional arguments, as if Reagent components are pure Clojure functions, others do it because React actually destroys props object, which means that a passed Clojure map will be destroyed, thus wrapping is required. So I’ve looking into possible ways of working around this limitation, mainly because I want component to be a simple defn that can take Clojure map of props, meaning there should be no macro that would glue props passing, or a runtime wrapping like in Reagent. Turned out it’s possible, although I wouldn’t say it’s the most safe way of doing it, since it relies on React’s internals, that can be changed at some point. But the idea is basically to reimplement React.createElement, because props are processed only once in that function call. Funny enough, React freezes JS object of props, to make sure it’s immutable. Here’s a simplified version

(defn- validate-child-keys [children-array]
  (doseq [^js node children-array]
    (when (and (= "object" (goog/typeOf node))
               (react/isValidElement node)
               (.-_store node))
      (set! (.. node -_store -validated) true))))

(when ^boolean goog.DEBUG
  (validate-child-keys children-array))

#js {:$$typeof (.for js/Symbol "react.element")
     :type component-type
     :key (:key props)
     :ref nil
     :props (dissoc props :key)
     :_store #js {:validated false}}

Roman Liutikov17:09:11

The above returns React Element object, with props map already assigned to an element. Not directly related, but required code here is to make sure that children keys are still properly checked in development. So statically defined children should be explicitly marked as validated, that’s what React does, so that it doesn’t complain about missing keys in those.


currentOwner might be hard to get at