0

Suppose having

(def defining-list `(def one 1))

How can I evaluate defining-list so that one becomes 1 ? (in clojurescript)

EDIT: I will give an idea of the broader image and what I am trying to accomplish here to avoid falling into an X/y problem.

I am trying to use cljsjs/material-ui from cljsjs package Instead of defining each time a react component to use it as following:

(def app-bar 
  (r/adapt-react-class (aget js/MaterialUI (name :AppBar)))

I would like to define all the components from an array of tags:

(def material-ui-tags '[AppBar Avatar Backdrop])

So I was thinking if it's possible to do this without the usage of a macro as I found this

Something like:

(doseq [component material-ui-tags]
  `(def ~(symbol (->kebab-case component)) (r/adapt-react-class (aget js/MaterialUI ~(name component)))))

But the above does only create a list of defs, I would like to evaluate these. In clojure eval would do the trick.

Jared Smith
  • 19,721
  • 5
  • 45
  • 83
m-arch
  • 65
  • 8
  • def is a constant. It never changes. Why would you want such a thing as a redefinition of a constant? – akond May 16 '18 at 06:51
  • The case I am looking for is little bit more complex, I am trying to achieve something like this but in clojurescript : https://stackoverflow.com/questions/2486752/in-clojure-how-to-define-a-variable-named-by-a-string – m-arch May 16 '18 at 07:16
  • @m-arch the short answer is to never ever do this in a browser. The answer involves `eval`, and ignoring the security aspect for a minute it will be a performance nightmare: you will have to ship the entirety of the clojurescript compiler over the wire and run it client-side. Just don't do it. What are you *actually* trying to accomplish here? Questions like this usually (but not always) indicate an [X/Y problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Jared Smith May 16 '18 at 14:02
  • @JaredSmith I edited my question to make things more clear and avoid the X/Y problem. But as far as I understood this should not be done? And is it possible to do it? – m-arch May 16 '18 at 14:34
  • @m-arch correct, don't do this. Just type out the boilerplate. Your editor should even be able to autogenerate it for you. – Jared Smith May 16 '18 at 14:39

1 Answers1

2

With reagent, you can use :> as shorthand for adapt-react-class as documented in https://github.com/reagent-project/reagent/blob/master/docs/InteropWithReact.md

Also, you can use dot notation with js/ and I think in shadow-cljs or cljs above 1.9.854 you can require to import the symbol instead of using aget.

In your case, it would be something like:

(ns example.core
  (:require [MaterialUI]))

(defn component-two []
  [:> MaterialUI/AppBar {:some-prop "some-value"}
    [:div "children-here"]])

(defn component-two []
  ;; If the require above doesn't work
  [:> js/MaterialUI.AppBar {:some-prop "some-value"}
    [:div "children-here"]])

To do what you wanted using def, you either need eval or macro. Eval is not ideal as Jared Smith explained in the comment.

The example that you linked from reagent-material-ui uses macro. Invoking a macro actually performs expansion and then evaluation. So your code needs to be something like this:

clj file

(def material-ui-tags '[AppBar Avatar Backdrop])

(defmacro adapt-components []
  (for [component material-ui-tags]
    `(def ~(symbol (->kebab-case component)) (reagent.core/adapt-react-class (aget js/MaterialUI ~(name component))))))

cljs file

(adapt-components) ;; your defs will be available below this line

(defn my-component []
  [app-bar ...])
Hendrik Poernama
  • 413
  • 3
  • 14