Thank you @lilactown @victorbjelkholm429 and @juhoteperi, I'm using devcards, so a simple solution is to create a component to be added as the root of the card for each card. So when eventually an error occurs I'll know exactly it happens.
What’s the preferred way to bundle component css/sass while using reagent? I’m used to vue.js, where you can easily bundle css that properly scopes to your components.
You can use webpack or other tool for processing sass and generating CSS and adding it to your index.html. But if you want scoped-css by component. You'll need to use a lib that does that like https://github.com/clj-commons/cljss, or maybe https://github.com/noprompt/garden.
In the company I work, we opted for using emotion (a JS library) inside clojurescript
Does emotion-js support media queries?
Hi, I'm having trouble creating a component that has an internal atom that is derived from some external atom. I hope this illustrates what I'm trying to do:
(defn confirm-input [outer-atom]
(let [inner-atom (rc/atom @outer-atom)]
(fn []
[:div
[:div "Outer: " @outer-atom]
[:div "Inner: " @inner-atom]
[:input {:type "button " :value "inc-inner" :on-click #(swap! inner-atom inc)}]
[:input {:type "button " :value "inc-outer" :on-click #(swap! outer-atom inc)}]])))
(defn render [] [confirm-input (rc/atom 2)])
The inner atom initializes to the value of the outer, but it doesn't update when the outer atom updates. I'm sure I'm missing something obvious here. Anyone got any pointers?I ended up adapting JP's solution using cursor to give a reusable solution:
(defn shadow [atom]
(let [initial-value (rc/atom @atom)
current-value (rc/atom @atom)]
(rc/cursor
(fn
([_k]
(when (not= @initial-value @atom) (reset! initial-value @atom) (reset! current-value @atom))
@current-value)
([_k v] (reset! current-value v)))
[])))
You want the inner atom to update when the outer atom changes? You are initializing the inner atom with the value of the outer-atom.
They are references to different values beyond that..
@jpsoares106 yeah, vue.js does custom elements really well (imo). They have a custom file format (`.vue` ) in which you define the html template, component css, and custom js together and webpack handles breaking it apart later. vue.js has taken that approach that separation of concerns doesn’t mean separate files (like angular uses)
If you want a value that is syncronized both inside and outside a component you could use the same atom.
Thanks @marques.goncalves.fel I’ll look into those suggestions. I know I could also use something like BEM, but that doesn’t solve the component css problem (just the page css problem)
Thanks for replying to me!
(defn confirm-input [outer-atom]
[:div
[:div "Outer: " @outer-atom]
[:div "Inner: " @outer-atom]
[:input {:type "button " :value "inc-inner" :on-click #(swap! outer-atom inc)}]
[:input {:type "button " :value "inc-outer" :on-click #(swap! outer-atom inc)}]])
using the same atom doesn't fit my use case really. I want to create an input where the user has to confirm the change they're making
So I don't want it to update the application state until the user clicks confirm
(defn confirm-input [outer-atom]
(let [inner-atom (reagent/atom @outer-atom)]
(fn []
[:div
[:div "Outer: " @outer-atom]
[:div "Inner: " @inner-atom]
[:input {:type "button " :value "inc-inner" :on-click #(swap! inner-atom inc)}]
[:input {:type "button " :value "inc-outer" :on-click #(swap! outer-atom inc)}]
[:input {:type "button " :value "Confirm" :on-click #(reset! outer-atom @inner-atom)}]])))
That's very close to what I'm looking for, thanks, but do you know of a way to have the inner atom update if something else changes the outer atom?
We use emotion
It works well
You want to use reagent.core/cursor
Seems like reagent.core/track
could be useful as well, if the value comes from a function. Haven't really used track myself though, so not super sure it's applicable here.
Ok, I'll look into those, thanks for the suggestions!
cursor and track might be better options, but for this specific case you could
(defn confirm-input [outer-atom]
(let [initial-state (reagent/atom @outer-atom)
inner-atom (reagent/atom @outer-atom)]
(fn []
(when (not= @initial-state @outer-atom)
(do
(reset! initial-state @outer-atom)
(reset! inner-atom @outer-atom)))
[:div
[:div "Outer: " @outer-atom]
[:div "Inner: " @inner-atom]
[:input {:type "button " :value "inc-inner" :on-click #(swap! inner-atom inc)}]
[:input {:type "button " :value "inc-outer" :on-click #(swap! outer-atom inc)}]
[:input {:type "button " :value "Confirm" :on-click #(reset! outer-atom @inner-atom)}]])))
I've got this example code in semantic-ui:
<Modal
trigger={<Button>Show Modal</Button>}
How do I do that in reagent?
is the { }
plain html syntax?
Ah, yeah. I've already tried that.
I don't know what the { }
syntax is
given the error I also tried passing a fn reference, but that gives the same error.
What's the link for the example code?
https://react.semantic-ui.com/modules/modal/#types-shorthand
You'll probably need to use reagent/dom-node
you need to use reagent.core/as-element
[:> Modal
{:trigger (reagent.core/as-element [:> Button "Show Modal"])}]
the semantic-ui modal component expects a React element as the prop
you need to convert the vector of data to a React element. that’s Reagents job
reagent doesn’t do this by default because most of the time, if you pass a vector as a prop you actually want a vector
not a React element
🙂
cool! thanks!
@lilactown that worked!
I have an off-topic figwheel question. What's the best way of resetting figwheel if (reload-config)
doesn't do the trick?
lol... what if deleting the target directory and restarting figwheel also doesn't have the desired effect?
that's a tough one. Did you something in the environment you're running it in? Are you applying the change in the right project?
getting any warnings/errors from figwheel?
it's not reporting any errors and it appears to run when I make changes, so the file-watcher seems to be working. Only the code it produces looks like it came from an old source file.
@doubleagent what about warnings? Figwheel prevents doing any builds if you're getting warnings
Really? The basic luminus template code produces a warning but it compiled anyway.
I have one warning, not in my code - but on a dependency.
var: clojure.string/replace-with is not public at line 327 ... cuerdas\core.cljc
it should, at least. Might just not recompile the ns the warning comes from, not sure about that
try :load-warninged-code true
https://figwheel.org/config-options.html#load-warninged-code
I created the file and added {load-warninged-code true}
.
Then I ran (reload-config)
. Didn't notice any difference from prior behavior.
I'm trying to learn Reagent, and I'm trying to work on the concept of mutable data. It seems like you want mutable data in different pieces, so that each component can re-render separately, but you also want mutable data in one place so that your application is simpler. What's a good way to reconcile these two ideas?
how far do maps get you?
Maps?
The two ways I've seen it are to have a bunch of atoms scattered around the code, or have one giant atom that holds the entire state of the program.
The first option makes it difficult to track down mutable data, the second makes it so when the state changes, the entire webpage has to reset, rather than just the part that uses the piece of state that was changed.
I haven't tried it, but I suppose you could use a regular map of r/atom's eg
{:a (r/atom 1) :b (r/atom 2)}
(swap! (:a x) inc)
(deref (:a x))
That does make more sense... One map to rule them all. XD
in theory that would solve both problems, but I have no idea about the ergonomics - how reasonable it is in practice.
I'm not very used to working with atoms, so this part of reagent is very confusing for me.
@doubleagent, it seems practical; after all, it's kind of like inverting the atom of a map into a map of atoms.
My guess is that this leads to a worse development experience than scattering vars around your code. cljr-find-usages
is going to give you a lot of things you aren't interested in, for example.
But ymmv.
Short of copying my code into a new project I believe I'm stuck.
No idea where figwheel is pulling it's cached code from.
I find that tying state to components (using component local state) helps me manage many different sources of state
so e.g. if I have some form state, instead of putting that in a top level (def form-state (r/atom {:name "", :age ""})
and having each component refer to form-state
directly
I’d rather put it inside of a form
component and have that component pass it to each part of the form as arguments
(defn form
[_]
(let [form-state (r/atom {:name "" :age ""})]
(fn [{:keys [on-submit]}]
[:div
[name-input {:name (:name @form-state) :on-change #(swap! form-state assoc :name %)}]
[age-input {:age (:age @form-state) :on-change #(swap! form-state assoc :age %)}]
[:button {:on-click #(on-submit @form-state)} "submit]))
this way you never need to go grepping for state, it’s either passed into the component as props or it’s created right there inside the component