This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-20
Channels
- # adventofcode (140)
- # beginners (107)
- # boot (120)
- # boot-dev (1)
- # clara (13)
- # cljs-dev (9)
- # clojure (107)
- # clojure-argentina (5)
- # clojure-art (16)
- # clojure-dev (23)
- # clojure-greece (19)
- # clojure-italy (5)
- # clojure-russia (2)
- # clojure-serbia (3)
- # clojure-spec (27)
- # clojure-sweden (1)
- # clojure-uk (15)
- # clojurescript (134)
- # cursive (5)
- # data-science (10)
- # datomic (23)
- # duct (28)
- # fulcro (48)
- # garden (5)
- # hoplon (2)
- # instaparse (1)
- # klipse (7)
- # leiningen (8)
- # lumo (36)
- # off-topic (72)
- # om (4)
- # onyx (37)
- # perun (4)
- # re-frame (64)
- # reagent (86)
- # remote-jobs (1)
- # shadow-cljs (59)
- # spacemacs (16)
- # sql (1)
- # uncomplicate (6)
- # unrepl (90)
If I have a list of components, I need to give each component a unique key in order to avoid the React warning. I was wondering, is it ok to convert the list of components to vector using into
? That way I don't have to give them the unique key. Like this:
(defn my-container [& content]
(into [:div {:class "my-container-class"}] content))
(defn page []
[my-container
[:div "Div 1"]
[:div "Div 2"]
[:div "Div 3"]])
Are there any downsides for this approarch, e.g. performance?The basic point is that react won’t re-render an item in a list if it has the same key, even if something is inserted or deleted, or if the order changes. If none of those things will ever happen with your list of elements, it is totally fine to give react the index as a key.
@lee.justin.m Yeah, the converting to vector with into seems to get rid of the warning. Just tried.
Indeed, the items in this case are static. Nothing is added or removed dynamically. Yeah, I see your point about giving the index as a key. Maybe I should do that instead.
Yea if they won’t change then using an index is perfectly fine. There is no difference unless a mutation is possible.
I think that what you did with into
will avoid the warning but not the actual problem. I think the warning is a heuristic that only pops up when you have a component with a bunch of elements that are the same type. But I don’t 100% understand what the deal is.
Cool, thanks!
I have an ajax call for a ui component. Problem is that ajax call is repeated nonstop and if I use dev tools my memory use will go up and to a grinding halt.
I’m trying to render a chart using recharts, but I’m not sure how to pass the component to Reagent.
Ostensibly in JSX the component would look something like:
<LineChart
width={400}
height={400}
data={data}
margin={{ top: 5, right: 20, left: 10, bottom: 5 }}
>
<XAxis dataKey="name" />
<Tooltip />
<CartesianGrid stroke="#f5f5f5" />
<Line type="monotone" dataKey="uv" stroke="#ff7300" yAxisId={0} />
<Line type="monotone" dataKey="pv" stroke="#387908" yAxisId={1} />
</LineChart>
(defn my-component
[]
(reagent/create-class
{:reagent-render
(fn []
[:BarChart {:width 500 :height 300 :data [{:name "a" :value 12}
{:name "a" :value 24}]}
[:CartesianGrid {:strokeDasharray "3 3"}]
[:XAxis {:dataKey "name"}]
[:YAxis]
[:Tooltip]
[:Legend]
[:Bar {:dataKey "pv" :fill "#8884d8"}]
[:Bar {:dataKey "uv" :fill "#82ca9d"}]
])}))
in my example i just have a name property, but if i did not want it, i would have passed an empty map
for reagent version later than 6.0 you can just use shorthand syntax of [:> cljsjs.recharts/BarChart]
release notes on it, https://reagent-project.github.io/news/news060-alpha.html
could you have a look at my question above? I seem to get a memory leak due to an ajax call
everytime comps changes it's going to cause components to re-render which of course will call your ajax call again, causing comps to change.... You have an infinite loop essentially.
Not sure what the intention is, but components would need a render function. The ajax call should be called outside that render function.
Well, it is sort of fine this way. If a new component is added to the database, it will instantly appear in the front end
perhaps but it is going to repeatedly fire that ajax call. If you want that real time behavior I'd move the ajax call outside of that components function and into something that fires it at more set intervals. then in your components function in the componentdidmount you can start the polling and on the unmount stop it. Or for even more realtime change it to using websockets but guessing interval polling would be good enough.
something more like this perhaps
(defn components []
(let [comps (r/atom nil)
_ (start-polling (fn [result]
(swap! comps assoc :data result)))]
(fn []
[:div.main.components
(map makecomponent (get @comps :data))])))
where in start-polling you'd do a window.setTimeout and do your ajax call
if you don't care about return value you can use an underscore
@eveko It is a naming convention (for unused bindings), _
is a normal symbol, you could use it to refer to the value (but that would be bad idea)
looks alright (I haven't tried it locally). Are you handling the nil case and returning an empty component in makecomponent?
what's the code look like that calls components-t?
tried this locally and it seems to work alright (just hard coded response from the ajax fn). Although technically to do this you'd want to probably bind the result of js/setInterval to a local var and clear it before creating new one.
(defn get-component-data2 [f]
(f [[:div "hello"]]))
(defn start-polling [fun]
(js/setInterval (fn [] (get-component-data2 fun)) 5000))
(defn makecomponent [c]
(println c)
(if (some? c)
c
nil))
(defn components-t []
(let [comps (reagent.core/atom nil)
_ (start-polling (fn [result]
(swap! comps assoc :data result)))]
(fn []
[:div.main.components
(map makecomponent (get @comps :data))])))
your interval created with js/setInterval is going to continue running so each update to the components is going to create a new one (but the old one's will still be running) unless you store it in a var and run js/clearInterval(my-interval)
i'd probably just use a regular atom....something like this:
(defonce interval (atom 0))
(defn start-polling [fun]
(js/clearInterval @interval)
(reset! interval (js/setInterval (fn [] (get-component-data2 fun)) 5000)))
cleaner option once you get it all sorted out would be to utilize your main components react lifecycle methods and return the interval id created in the componentdidmount and store that in your component state. Then in componentdidunmount you would call the clear. That would keep the code a bit more cohesive.
you migh thave a look through this....it shows you the different ways of creating reagent comps. Last way giving you full control of the react lifecycle methods: https://github.com/Day8/re-frame/wiki/Creating-Reagent-Components
I am planing to use the data in other ui elements in the future, so this works fine for now
Do folks have a favorite library for making xhr requests? I’m starting to use cljs-http, which seems fine, but wondered if others have experience with other libraries.
That's probably the most common other than just using google closure's xhr stuff directly, but cljs-http uses it under the hood.