reagent-project / reagent Goto Github PK
View Code? Open in Web Editor NEWA minimalistic ClojureScript interface to React.js
Home Page: http://reagent-project.github.io/
License: MIT License
A minimalistic ClojureScript interface to React.js
Home Page: http://reagent-project.github.io/
License: MIT License
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?
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?
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:
code is here:
https://github.com/gzmask/embodier/blob/master/src/cljs/embodier/core.cljs
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.
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! :-)
The wrapper for native React components doesn't track derefs. Maybe it should (if the overhead can be kept down)? Or at the very least there should be a warning (which could be made very cheaply).
See
https://groups.google.com/forum/#!topic/clojurescript/-KSbQ1kQWe8
React 0.9.0 was released today. It would be great if Reagent would be updated to use the latest version.
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"}}]]))
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.
Is this even possible? I know om stores everything in a global atom. Is it possible to do this in reagent as well?
(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.
I was reading the code and did a double-take on this line:
https://github.com/holmsand/reagent/blob/master/src/reagent/ratom.cljs#L265
Without deep understanding, but just based on the names involved, I would guess that perhaps the then
and else
should be reversed to become:
(let [runner (if (true? auto-run) auto-run run)
But I could easily be misunderstanding something here. I just didn't want to let it pass without noting it. Appols if this is noise.
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?
What's the best way to test the client side of Reagent-driven apps?
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)])
Reactjs has an animation addon that would be neat idiomatically use in reagent:
http://facebook.github.io/react/docs/animation.html
The problem solved by the addon is that if you CSS animate your exit transition the DOM component must not be removed until the animation is done, otherwise it just blinks out of existence.
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.
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.
Right now they get camelCased, and so dropped by React. Should also probably only camelcase keywords, and pass strings as-is.
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:
Steps to reproduce:
cd
into reagent/examples/simple
make
open index.html
in a different terminalIs 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.
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:
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
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?
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?
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.
[: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.
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.
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
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
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?
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)))
This is a question.
Wondering what I'm doing wrong here.
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
If I update "One" I have verified the atom is updated, but the screen rerenders with the original "One"
Cheers,
Jamie
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.
(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))
)
Is reagent/render-component
supposed to block (never returns) if I call it from a CLJS REPL?
Or have I screwed up the config?
I'm using https://github.com/cemerick/austin to set up the REPL.
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]
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?
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! :-)
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 :-)
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! :-)
See the reply to this question on google groups. Is reagent creating more components than necessary compared to om?
https://groups.google.com/forum/#!topic/clojurescript/sWJxg-2cahQ
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!
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!
(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.
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?
As far as I understand, the best way to move the Reagent repo into the reagent-project org is to
Any objections? Other ideas?
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:
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
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)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.