TIL: rum/local
adds its own watcher and forces update on the component. Leads to unexpected rerendering when you're actually only using the local state as coordination between children components.
This is what I expected rum/local
implementation to be..
so, rum/local
is exactly a clojurescript atom that you mix in, since it needs to generate for local scope on will-mount
. I reckon the rule should be consistent: if you want your component to react to any state change, use rum/react
- just a deref should always be assumed to be wrong (unless you specifically don't care about the reaction/update, that is)
passing around atoms and cursors, in my experience of rum at least, is completely normal and useful - but that's not really the point here. I'm more saying that the default behaviour of rum/local
mixing in an implicit rum/reactive
and rum/react
for its atom can be unexpected.. - of course, I've worked around it by implementing my own simplified version of rum/local
which we'll be using ubiquitously, but I mention it here as something for people to be aware of.
If you look at https://github.com/tonsky/rum/blob/gh-pages/src/rum/core.cljs#L335
It seems to indicate that deref
ing a rum/local
state is fine in the docstring, and that rum/react
is intended to be used with rum/reactive
and for rum/react https://github.com/tonsky/rum/blob/gh-pages/src/rum/core.cljs#L407
https://github.com/tonsky/rum/blob/gh-pages/src/rum/core.cljs#L409
yes - I'm saying that the current implementation of rum/local
is unexpected. it "works" to just deref, but it's treated as not only a local atom, but also an implicit local rum/reactive
- see the duplication: https://github.com/tonsky/rum/blob/gh-pages/src/rum/core.cljs#L353 and https://github.com/tonsky/rum/blob/gh-pages/src/rum/core.cljs#L394 - imo, the rum/local
's single job should be to provide a local component scoped atom that you can change. Its job should not be to also rerender the component if the atom changes.
Ya I agree with you, it's confusing
It makes sense for the use case of a component changing its own state, or wanting to share some atom with other components that will update the atom to change them
But definitely a bit confusing when you just want state, and not want reactivity
Would have been clearer to make it a normal local. And then if you want reactivity also make the component reactive and use react on the local
ye, that's what I would have expected - I've made my own version of rum/local
and changing all our usecases to that, since we rum/react
on everything (even local atoms) already.
That wouldn't cause a rerender when the state changes though would it?
no, but if you wanted that, you'd rum/reactive
on the component and rum/react
the local atom - as you'd any other atom
contrived example: the parent atom here coordinates two children - when you click the button only the local-view
should re-render and get a new value. the rand-int
on the button and parent shouldn't fire.
at least, my intuition of rum/local
says it shouldn't. But I'm wrong, and I don't imagine this can get changed without serious backward breaking problems.
Thinking of how react works, the button needs to re render to capture the new value of the val-atom
in it's closure. In react both components would re-render, I think rum/local
is supposed to work in a similar manner to useState
or this.state
in react...
Ah but I guess val-atom is a ref, maybe if you used the rum/static
mixin on button
it would not re-render every time it's props change as the ref passed as a prop would be equivalent?
Also I think rum/react
is used exclusively with clojurescript atoms, not rum/local
state, you can just deref local state with @val-atom
This is what I'm suggesting, although I would probably create a function in parent
to perform the swap!
in the scope of where the local state is defined and just pass that to the button to bind it to the on-click
handler of the nested :button
, I don't think passing around atoms is a good idea but I'm quite new to rum, that's more of a habit from working with react in JS.