GithubHelp home page GithubHelp logo

reagent-project / reagent Goto Github PK

View Code? Open in Web Editor NEW
4.7K 115.0 409.0 3.89 MB

A minimalistic ClojureScript interface to React.js

Home Page: http://reagent-project.github.io/

License: MIT License

JavaScript 1.59% Clojure 90.47% CSS 5.85% HTML 0.19% Shell 1.88% Just 0.03%
reagent clojurescript react frontend clojure hiccup

reagent's Introduction

Reagent

Run tests Clojars Project codecov cljdoc badge project chat

A simple ClojureScript interface to React.

Reagent provides a way to write efficient React components using (almost) nothing but plain ClojureScript functions.

Usage

To create a new Reagent project using Leiningen template simply run:

lein new reagent myproject

If you wish to only create the assets for ClojureScript without a Clojure backend then do the following instead:

lein new reagent-frontend myproject

This will setup a new Reagent project with some reasonable defaults, see here for more details.

To use Reagent in an existing project you add this to your dependencies in project.clj:

Clojars Project

And provide React using either npm (when using e.g. Shadow-cljs)

npm i react react-dom

or by adding Cljsjs React packages to your project:

[cljsjs/react "17.0.2-0"]
[cljsjs/react-dom "17.0.2-0"]

Note: Reagent is tested against React 17, but should be compatible with other versions.

Examples

Reagent uses Hiccup-like markup instead of React's sort-of html. It looks like this:

(defn some-component []
  [:div
   [:h3 "I am a component!"]
   [:p.someclass
    "I have " [:strong "bold"]
    [:span {:style {:color "red"}} " and red"]
    " text."]])

Reagent extends standard Hiccup in one way: it is possible to "squeeze" elements together by using a > character.

[:div
  [:p
    [:b "Nested Element"]]]

can be written as:

[:div>p>b "Nested Element"]

Since version 0.8: The :class attribute also supports collections of classes, and nil values are removed:

[:div {:class ["a-class" (when active? "active") "b-class"]}]

You can use one component inside another:

(defn calling-component []
  [:div "Parent component"
   [some-component]])

And pass properties from one component to another:

(defn child [name]
  [:p "Hi, I am " name])

(defn childcaller []
  [child "Foo Bar"])

You mount the component into the DOM like this:

(defn mountit []
  (rd/render [childcaller]
            (.-body js/document)))

assuming we have imported Reagent like this:

(ns example
  (:require [reagent.core :as r]
            [reagent.dom :as rd]))

State is handled using Reagent's version of atom, like this:

(defonce click-count (r/atom 0))

(defn state-ful-with-atom []
  [:div {:on-click #(swap! click-count inc)}
   "I have been clicked " @click-count " times."])

Any component that dereferences a reagent.core/atom will be automatically re-rendered.

If you want to do some setting up when the component is first created, the component function can return a new function that will be called to do the actual rendering:

(defn timer-component []
  (let [seconds-elapsed (r/atom 0)]
    (fn []
      (js/setTimeout #(swap! seconds-elapsed inc) 1000)
      [:div
       "Seconds Elapsed: " @seconds-elapsed])))

This way you can avoid using React's lifecycle callbacks like getInitialState and componentWillMount most of the time.

But you can still use them if you want to, either using reagent.core/create-class or by attaching meta-data to a component function:

(defonce my-html (r/atom ""))

(defn plain-component []
  [:p "My html is " @my-html])

(def component-with-callback
  (with-meta plain-component
    {:component-did-mount
     (fn [this]
       (reset! my-html (.-innerHTML (rd/dom-node this))))}))

See the examples directory for more examples.

Performance

React is pretty darn fast, and so is Reagent. It should even be faster than plain old javascript React a lot of the time, since ClojureScript allows us to skip a lot of unnecessary rendering (through judicious use of React's shouldComponentUpdate).

The ClojureScript overhead is kept down, thanks to lots of caching.

Code size is a little bigger than React.js, but still quite small. The todomvc example clocks in at roughly 79K gzipped, using advanced compilation.

About

The idea and some of the code for making components atom-like comes from pump. The reactive-atom idea (and some code) comes from reflex.

The license is MIT.

reagent's People

Contributors

cloojure avatar codingthat avatar danielcompton avatar davidjameshumphreys avatar deraen avatar dijonkitchen avatar dosbol avatar ducky427 avatar gadfly361 avatar hlship avatar holmsand avatar isker avatar jeaye avatar jimberlage avatar jmlsf avatar jonase avatar julianleviston avatar mike-thompson-day8 avatar mikew1 avatar moskvax avatar poernahi avatar rgkirch avatar robinnagpal avatar seancorfield avatar shaunlebron avatar troglotit avatar viebel avatar vitorqb avatar whoops avatar yogthos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reagent's Issues

LightTable live coding?

Hi there!

I'm considering Reagent vs. OM.
I'm using LightTable.

So far I haven't been able to successfully use Reagent with LightTable live coding.
With OM it works every time (following the first section in this tutorial: https://github.com/swannodette/om/wiki/Basic-Tutorial).

Any hints to getting it to work with Reagent? :-)

Thanks in advance - Reagent looks really promising by the way! :)

Best regards,
Henrik

ratom can not be a js object

I tried to bind a threejs scene object into a ratom. when being deref in a callback function it returns undefine.

When I can not let reagent re-render my three scene, I tried to use animation loop in a function. But this doesn't work too since inside the animation loop there are de-reference to ratoms such that the function got re-executed everytime ratoms changed. This would create infinite animation loops and the system slow down very fast.

My question is that:

  1. can I use threejs scene/object/renderers as ratoms and let reagent re-rendering handle the animation?
  2. if not, is there a way I can disable auto re-execution for my animation loop function since it already de-reference ratoms like 60 times per second?

code is here:
https://github.com/gzmask/embodier/blob/master/src/cljs/embodier/core.cljs

Support seq as component

The following code does not work:

(defn simple-component [sub]
    (remove nil? [:div sub [:p "look above"]]))

This is because remove returns a seq instead of a vector, this works:

(defn simple-component [sub]
    (vec (remove nil? [:div sub [:p "look above"]])))

could seq's be supported as components? Is there any reason why only vectors are supported?

Warning: Reactive deref not supported in seq

I see the warning "Reactive deref not supported in seq". Is this limitation fundamental to how the reagent atoms work? Or is it something not yet implemented?

In many cases it's easy to avoid the warning simply by lifting the deref out of the for loop. And if that doesn't work you can wrap your lazy-seq in a doall. I have yet to find a case where I can't get rid of the warning.

Would it be better to throw an exception instead of a warning? Or can the warning in some cases be safely ignored?

Best place to do an AJAX request?

From reading the Facebook React docs, I understand that the best place to do an AJAX request is in .componentDidMount().

Is there a recommended workflow or best practice for where to do an AJAX GET to provide data to a Reagent component?

The following works fine (populating an ratom) but doesn't seem very idiomatic:

(defn ^:export run []
  (do (ajax-request!) (render-component [component] ... ))

Apologies for clogging up GitHub Issues with a how to request!

Why the atom need to be global in this case

I have a widget where I declare an atom with let. It sets the color correct but changing the color in a setTimeout has no effect. Doing the same with a global atom works as expected.

;;(def color (atom "red"))
(defn widget[]
  (let[color (atom "red")]
    (js/setTimeout #(reset! color "lime") 500 )
    [:div
     [color-picker {:s selected}]
     [:div {:style {:background @color
                    :width "500px"
                    :height "500px"}}]]))

Atoms can't be initiated in a function or a let?

(def at (atom "hello"))

[my-awesome-widget at]

Works as expected.
However, if I try to create the atom in a function, or in a let, it doesn't work.

[my-awesome-widget 
  (let [aa (atom "hello")]
    aa)]

In the latter case, it seems that any attempt to change the atom (from within my-awesome-widget) will fail.

FRP (javelin) + cloact

Hi,

(Reposting it here from cljs list)

Thanks for cloact, its great !

I was comparing the BMI Calculator from hoplon and cloact, and could see that the hoplon approach was more simpler for one primary reason - their use of FRP (javelin) to tie in the model pieces.

So when a user change occurs, instead of calling change-bmi, the hoplon example simply changes the weight/height. This causes the respective bmi to change, which causes the ui to rerender.

Cloact currently uses an atom to propogate state changes, is it possible to swap it with the javelin implementation ?

Thanks,
Murtaza

Static and dynamic attrs can't be mixed

This id is lost:

[:div.content-field.user-content {:id editor-id} content]

This works ok:

[:div {:id editor-id :class "content-field user-content" } content]

Splitter Example

We're enjoying using reagent. Many Thanks. (Still being actively maintained, right?)

As part of our learning process, we've created a reusable component which is a vertical layout, with splitter. It would have been useful to us if there was a "place" containing example-components, like this one. A sub directory in reagent, perhaps?

For what it is worth (we are still learning), here is our offering, if you do decide to create something like this (we hereby donate it under your licence, for your use):
https://gist.github.com/mike-thompson-day8/8dcdee225e33743bc0f8

BTW, I believe this is also a really nice example of of reagent use, which should be showcased:

https://gist.github.com/allgress/11348685

DOM refs aren't accessible

React supports a ref attribute for gaining access to a specific DOM element in a component. In this example, I should be able to focus the input field after it is mounted in the DOM:

(defn login []
  [:form
   [:input#username {:type "text" :ref "username"}]])

(def login-with-focus
  (with-meta login
    {:component-did-mount (fn [this] (.. this -refs -username (getDOMNode) (focus)))}))

It doesn't work because cloact implicitly creates a component for each of the vectors in the render function. The React Chrome Plugin shows this behavior:
React Console
The ref is added to the highlighted component which is implicitly created instead of being attached to the login component (called "cloact1").

I'm thinking this isn't an easy problem to solve. It seems ideal to avoid creating the implicit components but the current design works with the assumption that every child should be promoted to a component if it isn't already one.

Sablono might be helpful here because it can convert Hiccup into a nested tree of React.DOM.* calls.

BTW I really like cloact and it feels like the most idiomatic ClojureScript interface to React.
Matt

Not render when used js/setTimeout

Why it does not work properly?

(defn timer-component []
  (let [seconds-elapsed (atom 0)]
    (fn []
      (js/setTimeout #(swap! seconds-elapsed inc) 1000)
      [:div
       "Seconds Elapsed: " @seconds-elapsed])))

(defn home []
  [:div 
   (timer-component)])

When it works.

(defn home []
  (timer-component)])

And this

(defn timer-component []
  (let [seconds-elapsed (atom 0)]
    [:div
       "Seconds Elapsed: " @seconds-elapsed])))

(defn home []
  [:div 
   (timer-component)])

"Uncaught Error: Invalid arity: 1" when using metadata on a component

Okay, this is weird...

For an unknown reason, when I add metadata to a component (say :component-did-mount), I get an error when trying to load the JS:

"Uncaught Error: Invalid arity: 1"

I get the same error with an empty metadata.

(defn test-div []
  [:div "hello"])
;; this one works

(def test-div-2
  (with-meta
    test-div
    {:component-did-mount #(.log js/console "asd")}))
;; throws an error

(def test-div-3
  (with-meta test-div nil))
;; throws an error

What's worse is that I've already used this method before, so I know it should work!

Any clue on what might be causing this?

Question: Supported HTML Tags?

Sablono's Readme says:

HTML Tags

Ŝablono only supports tags and attributes that can be handled by
React. This means you can't have your own custom tags and attributes
at the moment. For more details take a look at the
Tags and Attributes
section in the React documentation.

Do we have such limit in Reagent? Sorry if the question is too silly.

Callback on re-render

Is it possible to hook re-render and execute arbitrary function? Not particular component (as if setting componentDidUpdate handler), but any re-render done by reagent?

React 0.12 Support

Hi All,

I just read up on the project stuff about moving to an org - exciting stuff!

I notice that thread stemmed from upgrading to 0.11, which is now done - but React 0.12 has been released.

From a read of the reagent internals, I'm impressed with the novel approach. I'm new to reagent but i've done quite a lot of pure JS React stuff, so I'm fairly familiar with the react internals.

0.12 is mostly backwards compatible, but will produce a bunch of warnings about things that will be removed in 0.13. Some of these are simple renames, but the headline change is around the relationship between the virtual dom representation, react classes, and JSX.

The headline of this is

Composite Component functions can no longer be called directly - they must be wrapped with React.createFactory first. This is handled for you when using JSX.

The change a step towards enabling better interop with compile-to-JS languages, and removing the need for React.createClass.

In the latest version of React, the JSX compiler now produces slightly smarter output:

> echo '<div className="abc">Stuff</div>' | ./node_modules/.bin/jsx
built Module("<stdin>")
React.createElement("div", {className: "abc"}, "Stuff")

> echo '<MyComponent data={stuff}>More Stuff</MyComponent>' | ./node_modules/.bin/jsx
built Module("<stdin>")
React.createElement(MyComponent, {data: stuff}, "More Stuff")

This is much closer to how reagent currently works internally, so should allow some simplification of the impl.template namespace.

deftype/defrecord/reify renderable?

Would it be possible to check for ifn? instead of fn? (at least here and here)? This way you could use deftype/defrecord/reify to create renderable types:

(deftype Foo [x y z]
   IFn
   (-invoke [hi]
       [:span hi [:em x]]))

and

(def foo (reify
           IFn
           (-invoke [_] [:span "reified!"])))

Reagent (React.js) messes up the scrolling position

When updating a component bigger than the window (a tall table for example), the scrolling position is modified.

This can potentially affect even smaller objects if the user has a small viewport.

In vanilla cljs/js, I would simply wrap my function to restore the scrolling position afterward. however, I don't really know what to do in Reagent considering that changes from anywhere can trigger a DOM modification.

Should I use something like the :component-did-mount, or should Reagent automatically save the scrolling position?

Allowing lifecycle metadata on inner component fns

Hi Dan, hope you're well!

Think this might be clearer to explain with an example. It's currently possible to write something like:

(with-meta
  (fn outer-component [arg1 arg2]
    (let [local-state (atom {})] ; Perform setup, etc.
      (fn inner-component [arg1 arg2]
        [:div (str arg1 "," arg2 "," @local-state)])))
  {:component-did-mount (fn [this])})

This works, but the :component-did-mount fn has to do w/o access to local-state.

It's be nice to support something like this:

(fn outer-component [arg1 arg2]
  (let [local-state (atom {})] ; Perform setup, etc.
    (with-meta
      (fn inner-component [arg1 arg2]
        [:div (str arg1 "," arg2 "," @local-state)])
      {:component-did-mount
       (fn [this]
         ;; Has access to local-state (but doesn't currently trigger)
         )})))

I.e. by allowing lifecycle metadata on the inner component, we gain the ability to share local setup state with the mount fn.

Does that make sense?
Think it'd be feasible?
Any downsides?
Would a PR be welcome?

Thanks a lot! No urgency on this at all, know you've been busy.

Cheers :-)

Updating app-data Ratom succeeds, but page rerenders with original data

This is a question.

Wondering what I'm doing wrong here.

  • The setup: data is a tree of n-depth. Components can have a list of children that are also components. My sample data has 4 levels.
  • Each item's data is displayed as text of a few attributes
  • Clicking a row enables edit mode with input fields for each attribute

As text is typed into a field (:name only right now), app-data is updated using update-raw-product. I've verified that items are updated properly in app-data, so the state is changing.

However, when rerendering, the original data is displayed. I've tried a couple of approaches, the current probably being the simplest, but can't see what I'm doing wrong.

Heres a gist:

https://gist.github.com/jamieorc/980f033af5bf2a8737db

screen shot 2014-05-23 at 12 09 39 pm

If I update "One" I have verified the atom is updated, but the screen rerenders with the original "One"

Cheers,
Jamie

Advantage of exporting run function as entry point?

Hi,

I'm learning ClojureScript & Reagent making a game and I notice you use this construct at the bottom of todomvc.cljs:

(defn ^:export run []
  (reagent/render-component [todo-app] (.-body js/document)))

... which you then call in the HTML:

<script type="text/javascript" src="target/client.js"></script>
<script type="text/javascript">
  todomvc.run();
</script>

I'm assuming this is to facilitate testing / loading the file into a REPL? Chord examples uses a different approach which I suppose would come out something along the lines of this:

(set! (.-onload js/window)
      (fn []
          (reagent/render-component [todo-app] (.-body js/document))))

Variants of that approach is what I've seen in most examples. Is there any practical advantages to your approach that you can share?

Generating components that are compatible with React.isValidClass

I'm trying to interop with a 3rd React component that expects component passed to it to pass React.isValidClass(my_component) === true.

The source of that React method is:

ReactDescriptor.isValidFactory = function(factory) {
  return typeof factory === 'function' &&
         factory.prototype instanceof ReactDescriptor;
};

Reagent seems to generate components as an object instead of a function. Here is my code:

(ns mytest.core
  (:require [reagent.core :as reagent :refer [atom]])

(defn home []
  [:div [:h1 "Home Page placeholder"]])

(reagent/as-component (home)) ; => #<[object Object]>

(.isValidClass js/React (reagent/as-component (home))) ; => false

I've looked through the Reagent code base, and have been unable to find an API to generate a component that will pass this test.

React 0.11.2
Reagent 0.4.3

Custom tags

When doing server side rendering, to use components you have to manually traverse the generated html and enhance the special nodes, as you cannot return a reference to a fn from the server.

Example:
(defn my-component [n]
[:span (str n)])

Returned from the server:
[:div [:my-component 3]]

From there I manually scan it and replace :my-component for the fn reference.

Something like this would solve the problem and avoid to scan:
(r/register-component! my-component :my-component)

React 0.11 is out

The big change, or the change that will be most noticable by us reagent users, is the fact that React now renders null to <noscript/>. This should be pretty sweet, as it allows us the use of when and when-not without removing nil from the resulting vector.

Sets of classes aren't properly joined

[:div.test {:class #{:foo :bar}}] very nearly works as one might expect, but it comma separates the classes, leaving you with <div class="test foo,bar"/> rather than the correct <div class="test foo bar"/>

It would be nice if this was either explicitly forbidden (errored out) or worked properly for classes.

Can't get nested components to work

Is this something that should work or am I missing something:

(defn my-li [props s]
  [:li s])

(defn my-list [props elems]
  [:ul {:style {:background-color "red"}}
   (seq elems)])

(defn ^:export start []
  (r/render-component
    [my-list
      [my-li "foo"]
      [my-li "bar"]]
    (by-id "app")))))

Note that if I use :li directly instead of [my-li ...] everything works as expected.

Move Reagent to reagent-project

As far as I understand, the best way to move the Reagent repo into the reagent-project org is to

  1. Transfer ownership to reagent-project
  2. Fork the new reagent-project/reagent into holmsand/reagent
  3. Setup gh-pages in that fork to do a redirect to the reagent-project site

Any objections? Other ideas?

top-part of html doesn't change

(def top-part (atom [:p "Original top part"]))

(def simple-component (atom  
  [:div
   @top-part
    [:p.someclass
      "I have " [:strong "bold"]
      [:div {:style {:color "red"}} " and red "] "text."]]))


( reset! top-part
     [:div
    [:p "Changed top part!"]])




 (defn simple-parent []
    [:div
      @simple-component
   ])

 (defn ^:export main []

     (reagent/render-component [
                          simple-parent
                           ]
                        (.-body js/document))
)

No need to define externs?

Hi Dan, purely out of curiosity, I notice that it's unnecessary to define externs when using the advanced compilation mode of the Google Closure Compiler with reagent projects. I'm wondering how you achieved this.

Thanks.

Uncomfortable name?

Hi, this project looks cool. But, I don't know if it's just me, but the name "cloact" sounds very uncomfortable to me, because it's close to "cloaca" (I'm not a biologist, but I do remember high school biology). Just letting you know.

Tracking down unique key prop violations

Hi Dan,

Was just wondering if you had any suggestions on how best to track down the cause of messages like "Each child in an array should have a unique "key" prop. Check the render method of :li"

When I've got hundreds of :li tags, it's sometimes quite painful trying to isolate the particular tag(s) where there's a key conflict or missing key.

As I understand it (?), the error messages when using JSX include the component's displayName to help in cases like this. Have played around a little with the Chrome React developer tools, but that doesn't seem (?) to help with this much. Any ideas?

Thanks a lot, cheers! :-)

Misunderstanding something about :key prop passing

Hi Dan!

(defn foo  [i] [:li {:key (str "foo" i)} (str i)])
(defn foo1 []  [:li {:key "foo1"} "1"])

(reagent/render-component
  [:div "Hello,"
    ;; [:li {:key "foo1"} "1"] ; Gets :key
    ;; (foo1)                  ; Gets :key
    ;; (foo 1)                 ; Gets :key
    [foo1]     ; Doesn't get :key
    ;; [foo 1] ; Doesn't get :key
  [:li {:key "foo2"} "2"]]
  container)

So it seems that () component-calling forms keep their :key props, whereas [] component forms don't. Is that the expected behaviour?

My understanding was that the only difference between the () and [] calling forms was that the latter caches itself for rendering when its input args don't change. Am I missing something obvious here?

Thanks a lot, cheers! :-)

JS Error upon running the "simple" example

After compiling the clojurescript and opening the example.html file in Google Chrome (I have not tested other browsers), I am met with the following error:

a336_zx13qsffraznz2hu8vsuruh361tolmlkdbmroc

Steps to reproduce:

  1. Clone holmsand/reagent
  2. cd into reagent/examples/simple
  3. run: make
  4. After clojurescript successfully compiles, run: open index.html in a different terminal
  5. Open browser and inspect the console.

How to add child dynamically

In React I can add children like this:

<ol>
  {this.results.map(function(result) {
    return <li key={result.id}>{result.text}</li>;
  })}
</ol>

How would the equivalent look like with Cloak.

`simple-example` reports `undefined` function `mountComponentIntoNode`

Apologies in advance since I am a total n00b to ClojureScript and Reagent, so this is probably due to my ignorance rather than a bug. I tried to run the simple-example you provide, and it fails when calling nextComponent.mountComponentIntoNode with the error undefined is not a function. I nosed around a bit in the generated JS, and it seems like it is expecting the component defined by the first parameter to reagent/render-component to have the mountComponentIntoNode method when compiled into JS. When I changed the code to match the example in the README (calling reagent/render-component [simple-example]... instead of passing in an anonymous function) it works fine.

Is the example out-of-date or do I have something configured wrongly?

Should Reagent re-render after clicking the button in this snippet?

The following does not seem to work. I'm fairly new to Reagent, so my question is, should it work?

(def show? (atom true))

(defn ^:export run []
  (reagent/render-component
   [:div (str @show?)
    [:button {:on-click
              (fn [e] (swap! show? not))}
     "swap"]]
   (.-body js/document)))

dangerouslySetInnerHTML support?

Hi Dan,

This isn't obvious to me - can you recommend the easiest way of providing text content in a component that'll be rendered as arbitrary HTML?

(defn my-component [] [:div "<strong>I want to see this in bold</strong>"])

Maybe we could do something with metadata to indicate that an element's content should be set with dangerouslySetInnerHTML? Was thinking along the lines of ^:html [:div "..."] but not sure how feasible that'd be.

Cheers! :-)

Let div be default html tag

So, in hiccup i can write [:.some-class] and this implicitly means [:div.some-class]. It's a minor thing, but something I've grown accustomed too. Would it be possible to drop 'div' in a future release?

Btw, reagent rocks!

Does not support all React Attributes correctly

According to:
http://facebook.github.io/react/docs/tags-and-attributes.html#supported-attributes

React supports all data-* and aria-* attributes as well as every attribute in the following lists.
The problem is, in impl/template.cljs, the undash-prop-name function does not take into account whether or not the name starts with data.

I don't think facebook react likes dataBlahBlah going into it. I suggest that all data and aria attributes are not converted away from dashes.

This convenience for clojure/lispy names has come to a frustration here since I don't see any way around it..


This was in the cloact repo until I noticed that it has been moved here.

Nil Value Not Updating Text Input

(def value (atom {"a" "Original Content"}))

(defn content []
  [:div
  [:input {:type "text"
        :value (get-in @value ["a"] "") ; <<<--- DEFAULT VALUE SHOULDN'T BE NECESSARY
        :on-change #(swap! value assoc "a" (-> % .-target .-value))
        }]])

(defn clear-content []
  (reset! value nil))

The above code gives a text box which responds to user input and can be cleared by calling clear-content. However if no default value is included

:value (get-in @value ["a"])

instead of

:value (get-in @value ["a"] "")

then calling clear-content results in value returning a null value and not clearing the text box as it should. Subtle but annoying.

Thanks for the great library BTW.

Can't validate inputs

I'm not exactly sure how to explain this, but the code below doesn't behave like I'd expect. It seems to conflict with React's idea of controlled components.

(defn validated [new-value old-value]
  (if (re-find #"\d" new-value) old-value new-value))

(defn atom-input [value]
  [:input {:type "text"
           :value @value
           :on-change #(reset! value (validated
                                       (-> % .-target .-value)
                                       @value))}])

(defn shared-state []
  (let [value (atom "foo")]
    (fn []
      [:div
       [:p "The value is now: " @value]
       [:p "Change it here: " [atom-input value]]])))

So, given that code, I'd expect you could never enter digits in the input field. However, digits do appear there. (The validation runs, and the value atom never has digits, but the input doesn't always reflect this.)

I wonder if the reason is that if an input has an on-change then this code forces the input's value to be whatever text has just been entered. I'm not sure that makes perfect sense, because the next step would be to call on-change, which should trigger a re-render, because it reset!s the atom. It may be more complicated... something to do with how Reagent models input components or the timing of the input-handle-change code.

I'd be willing to try to write a test and look for a fix, but I can't figure out how to run the tests. Would you give me some pointers?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.