This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-07-29
Channels
- # aleph (2)
- # bangalore-clj (1)
- # beginners (9)
- # boot (18)
- # clara (3)
- # cljs-dev (21)
- # cljsjs (2)
- # clojure (137)
- # clojure-spec (2)
- # clojurescript (65)
- # clr (1)
- # copenhagen-clojurians (11)
- # core-async (20)
- # datascript (3)
- # lein-figwheel (1)
- # leiningen (4)
- # luminus (4)
- # lumo (1)
- # off-topic (38)
- # onyx (1)
- # parinfer (4)
- # pedestal (9)
- # protorepl (8)
- # re-frame (4)
- # reagent (92)
- # ring-swagger (2)
- # rum (1)
- # unrepl (40)
- # vim (16)
- # yada (1)
So the components rerender when a reagent/atom changes, if they deref the atom. So must I split up my state into several atoms to avoid redrawing everything all the time? I prefer to have one atom for the whole app.
@oskarkv that's what cursors are for
Huh, I see :exclusions
and empty react namespaces mentioned here, luckily we are getting very close to fixing this properly: https://github.com/reagent-project/reagent/pull/306
I'm thinking 0.8 will include only this change, as this will require ClojureScript 1.9.854 and it will take some time for everyone to upgrade to that
Would be cool if someone can test the change with :target :nodejs
or Electron. I have tested with npm-deps and Cljsjs package.
Or React-native. I don't have much idea how that works.
@juhoteperi 0.8.0-snapshot sounds like a great idea!
does this mean you won't be able to use Reagent without a node_modules folder anymore?
As the PR description mentions, (:require [react-dom :as react-dom])
works with new Cljsjs packages, node_modules and NodeJS target
It generates different JS code depending on the environment
This will need some documentation and lots of Cljsjs updates, because every Cljsjs React addon package needs to be updated to use new name, react
instead of cljsjs.react
The new name is required so that it matches with npm name
in cljsrn, people typically get their react using (js/require "react")
which works in figwheel as well as in production bundles
Hmm, I will have to investigate if it would be possible to provide both cljsjs.react
and react
from same foreign-lib so that existing react-* packages would work
Do React-native projects use :target :nodejs
, if so, (:require [react :as react])
will generate require("react")
call
no they don't normally
Hmm, well, then this will need a bit more work
I mean we'll need to update re-natal accordingly
I still don't understand fully how "npm-deps" works
does it generate js/require
calls?
So there are several different things
you just said that
:npm-deps
is just about automatically installing npm packages when running Cljs
installing as in "the cljs compiler actually shells out to npm"?
wow that's wild
Separate to that, Cljs compiler will index node_modules
and convert required CommonJS modules to Closure modules
But :npm-deps
doesn't need to be used
interesting
It is enough that packages are present in node_modules
dir
do you propose we do that in cljsrn?
i.e. convert react to a closure module?
If there is (:require [react])
, the logic goes something like
1. Is there Cljs namespace or Closure Module by the name
2. Is there Node package in Node modules
3. Is there foreign-lib which provides this name
I don't know how React-native works
There are probably people on #cljs-dev who know more about this
it'd be a good idea to give it a try but i'm not sure i'll have time to do that soon
my worry is that other npm dependencies (e.g. react-native, or any kinds of react-native packages) won't find the same React as Reagent
it's a common issue that a JS env includes multiple instances of React, which always causes problems
I'm not sure how Npm handles case where you have direct dep on React and other packages depend on other version, but I think Cljs (and thus Reagent) will use the top-most version (direct dependency)
Anyway there's no use in speculating, someone will have to try to get re-natal working with 0.8.0-SNAPSHOT
This could make things a lot cleaner, so thanks for putting in this work juho
@juhoteperi I've logged an issue in re-natal: https://github.com/drapanjanas/re-natal/issues/128
@deadghost untested, but if you wanted to use a component-local ratom, it'd be something like this
(defn counter []
(let [counter-ratom (reagent/atom {:count 0})]
(fn []
(let [count (get @counter-ratom :count)]
[:div
[:div (str "The current count is: " count)]
[:button {:on-click #(swap! counter-ratom update :count inc)}
"Increment count"]]))))
@gadfly361 I think the trickier part is where and how to do the inc
to get a correct count of re-renders
ah ok, i understand now, you literally want to count re-renders. Hopefully someone can help 🙂
@deadghost search here for :reagent-render
- I think that's your ticket https://github.com/Day8/re-frame/wiki/Creating-Reagent-Components
oh wait that might be reframe only sorry
now I think it's pure reagent (that part at least)
right now I'm thinking a form 3 component with a closure plus :component-will-update
To count renders ....
(defn counted []
(let [render-count (reagent/atom 0)]
(fn []
(swap! (swap! render-count inc)) ;; <------- count renders
[:div
[:div (str "The current render count is: " @render-count)]])))
* warning parens might not be balancedIe. each time the render function is called, inc
The only way a component can get re-rendered is for its renderer to get called
So put your inc
in there
Oh, yeah, one swap
okay, this is saner ...
(defn counted []
(let [render-count (reagent/atom 0)]
(fn []
(swap! render-count inc) ;; <------- count renders
[:div (str "The current render count is: " @render-count)])))
Yes it would, sorry
But, if you are showing the count AND counting, then that's unavoidable
(defn show-counter
[r]
[:div "Count is" (str @r)])
(defn counted []
(let [render-count (reagent/atom 0)]
(fn []
(swap! render-count inc) ;; <------- count renders
[show-count render-count])))
Now there's no infinite loop
well in that case, I suppose render-count
can't be component local as it needs to get passed into show-counter
It can be component local, but you will just need a reason for the component to update by either passing in another atom that it derefs, or passing in some argument that changes ... something along these lines seems probable since there would be no use-case to count a components renders that never rerendered
@deadghost this is a working example of counting the rerenders from two sources based on what @mikethompson showed above
(defonce app-state
(reagent/atom {:foo 0
:bar 0}))
(defn show-count [r]
[:div "Count is" (str @r)])
(defn counted [ratom]
(let [render-count (reagent/atom 0)]
(fn [ratom]
(let [{:keys [foo
bar]} @ratom]
(swap! render-count inc)
[:div
[:div "foo count is: " foo]
[:div "bar count is: " bar]
[show-count render-count]]))))
(defn page [ratom]
[:div
[:button {:on-click #(swap! ratom update :foo inc)}
"Increment foo"]
[:button {:on-click #(swap! ratom update :bar inc)}
"Increment bar"]
[counted ratom]
])
(defn reload []
(reagent/render [page app-state]
(.getElementById js/document "app")))
(defn ^:export main []
(reload))
why does it not go into an infinite loop when show-count
is turned into a separate component and passed the atom?
if the deref of render-count belonged to counted
then everytime render-count was swapped, it would tigger a rerender of counted
, which would then tigger another increment, etc. However, with the deref of render-count in a child component, then counted
is not rerendered when render-count is incremented
so what you're saying is, it's possible for child components to be re-rendered more times than the parent
perhaps i am misspeaking tho, but the deref in a child component is the secret sauce as i understand it. please correct if i am wrong @mikethompson