reagent-project / reagent

A minimalistic ClojureScript interface to React.js
http://reagent-project.github.io/
MIT License
4.76k stars 415 forks source link

(improvement suggestion) `:<` as a shortcut for reagent.core/as-element #411

Closed piotr-yuxuan closed 4 years ago

piotr-yuxuan commented 5 years ago

This would be symmetrical to :>. I use Material-ui and find myself using reagent.core/as-element quite often for React interop.

This would likely imply to modify reagent.impl.template/vec-to-elem.

Deraen commented 5 years ago

Could you provide some usage examples?

Deraen commented 5 years ago
;; Current as-element example
[:> mui/Chip
 {:icon (r/as-element [:> mui-icons/Face])}]

;; Better written as:
[:> mui/Chip
 {:icon (r/create-element mui-icons/Face)}]]

Though as element doesn't make sense in this example, because Face is already a React component. better example is case where the component is Reagent fn:

(defn foo-icon []
  [:span.caret])

;; Current as-element example
[:> mui/Chip
 {:icon (r/as-element [foo-icon])}]

;; Proposal
[:> mui/Chip
 {:icon [:< foo-icon]}]]

Note that this couldn't be implemented in vec-to-elem because that is only used to translate Hiccup data to React elements, and the property map is not Hiccup. Properties are converted through convert-props / convert-prop-value and I'd be very careful about trying to convert some vectors inside properties to React elements automatically, it could easily affect vectors that shouldn't be converted as we can't know which properties are supposed to be elements.

piotr-yuxuan commented 5 years ago

I didn't expect so a swift response! You nailed it, provided examples are my most common use-case.

poernahi commented 5 years ago

One use case I can think of is interop with function-as-child-component pattern that is gaining popularity in the JS world. Example with react-apollo:

JSX

<Query query={SOME_QUERY}>
  {({data}) => (
    <div>
      {/*some nested components...*/}
    </div>
  )}
</Query>

Current CLJS

[:> Query {:query some-query}
  (fn [props]
    (r/as-element
      [:div
        #_[:some-nested-components]]))]

Proposed CLJS

[:> Query {:query some-query}
  (fn [props]
    [:< :div
      #_[:some-nested-components]])]

I'm personally not sure if I favour one over the other..

Deraen commented 5 years ago

@poernahi The version in your proposal is not feasible to implement. Reagent can't easily modify the return values of functions, unless the function is wrapped in function call (like as-element or reactify-component). And going through all component children and trying to detect which functions to modify would be hard and have bad performance.