简体   繁体   中英

Deriving static CSS from React components in ClojureScript

I've been playing around and thinking about using React through its various abstractions in ClojureScript, Reagent, Rum, Re-frame and Om. But there's one thing that I'm not sure that either adresses, perhaps because its a separate concern depending on how one looks at it, and that is effectively including styling in components. Though it is also entirely possible that it something I've overlooked, but on to the actual question:

Is there some way to have the static parts of styles given to React compiled to per component CSS classes instead of being in-lined in each instance of the component?

Time for an example! Lets take a list where each item should be styled a specific way:

[:ul
 (for [i (range 3)]
   [:li {:style {:background-color (str "rgba(0, 0, " (* i 70) ", 255)")
                 :color "lightgrey"}}
    i])]

Using Reagent the above Hiccup would be rendered as:

<ul>
  <li style="background-color: rgb(0, 0, 0); color: lightgrey;">0</li>
  <li style="background-color: rgb(0, 0, 70); color: lightgrey;">1</li>
  <li style="background-color: rgb(0, 0, 140); color: lightgrey;">2</li>
</ul>

As we can see rule deciding color could be extracted into a CSS class rule with that class attached to the element. In this specific case the differece in HTML size wouldn't be much, but each rule or instance of the component makes the gap larger.

So to sumrize: I like the idea of keeping everything related to a component inside that component, including the style; I just don't like inlining and repeating what doesn't have to be repeated. And with styles declared in Clojure data structures one could manipulate these using the Clojure core library, which is nice.

If you are using Om Next then you could use the fulcro-css library. Here is an example component copied straight from the link:

(defui ListItem
  static css/CSS
  (local-rules [this] [[:.item {:font-weight "bold"}]])
  (include-children [this] [])
  Object
  (render [this]
    (let [{:keys [label]} (om/props this)
          {:keys [item]} (css/get-classnames ListItem)]
      (dom/li #js {:className item} label))))  

, which will result in the following css:

<style id="my-css">
.fulcro-css_cards-ui_ListItem__item {
  font-weight: bold;
}
</style>

This will be the generated DOM if the parent of ListItem rendered an unsigned list ( <ul> ) containing two ListItem s:

<ul>
  <li class="fulcro-css_cards-ui_ListItem__item">A</li>
  <li class="fulcro-css_cards-ui_ListItem__item">B</li>
</ul>

So the style is kept inside the component and turned into css classes, thus avoiding inlining repetition.

Here both A and B will be rendered in a bold font.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM