This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-03-02
Channels
- # ai (5)
- # announcements (1)
- # babashka (8)
- # beginners (16)
- # clojure (21)
- # clojure-europe (3)
- # clojure-norway (6)
- # clojure-uk (1)
- # datomic (3)
- # events (4)
- # figwheel-main (5)
- # fulcro (10)
- # jobs (1)
- # lsp (26)
- # missionary (5)
- # pedestal (1)
- # polylith (3)
- # portal (28)
- # practicalli (1)
- # reagent (37)
- # reitit (1)
- # scittle (24)
- # tools-deps (7)
Is there a way to change the comparison operation of ratoms, without creating a custom implementation from scratch?
Say it has to store a JS object, which seems to only trigger from identity checks (ie same object but changed props doesn't trigger, but entirely new object does); use-case is storing objects coming from browser APIs directly, without the js->clj transform (because it loses the associated state)
Yeah it's one of these cases being limited by the existing API; think not having control over the objects, but having it over the function updating them, where it can trigger the watchers
It's a sensible limitation though: • Changing the comparison algorithm will change how your whole app works, with potential unforeseen consequences • What you have encountered is very, very rare • There are ways around it that are very easy to implement
ah i don't mean globally change it, but only for a specific ratom
kinda like react let you set the comparison function per-component, but in this case it happens at reagent's level
the default is good in the general case, but not in custom domain specific ones
You can use React's lifecycle functions just fine. And hooks. If feasible, I would still go with some explicit "dummy" ratom that stores all values that, when changed, should lead to a re-render. It would only be deref'ed in the view but not actually used. What's used is the ratom (which can now potentially be a regular atom) that stores the original data.
ah yeah, this all happens before hitting react at all, doing it in components would duplicate the checks
i had some success creating a custom ratom type, but it also requires copying private reagent implementation functions into app namespaces
> ah yeah, this all happens before hitting react at all That puzzles me. You want to trigger a re-render but before React is reached?.. What are you actually trying to do?
ratoms can be chained, not all resets and swaps get to react
So it's not about re-rendering at all but about triggering a watcher somewhere? The same mechanism could be used then - wrap the original and the "dummy" ratom in a reaction, that's it.
ah yeah i could look into that
I'm working on a reagent project where I need to initialize a component, [canvas-wrapper]
, only once and then render it within two different parent components, depending on the application state.
The goal is for canvas-wrapper
to remain mounted at all times, avoiding re-initialization or remounting as the state changes between the two parent components.
However, in my current implementation, the component obviously gets recreated each time the state changes.
I'm looking for a way to maintain the same instance of canvas-wrapper
across these two different components without it being re-initialized upon state changes. Any suggestions?
Here's a simplified version of the code illustrating the issue:
(if @show?
[panel1 [canvas-wrapper]]
[panel2 [canvas-wrapper]])
If the only reason is to preserve the state of the <canvas>
element, you can do that without preserving the React instance itself.
> If the only reason is to preserve the state of the <canvas>
elem
Yes
An alternative is to use portals, although I've never used them myself: https://react.dev/reference/react-dom/createPortal I would definitely try to go the simpler route of driving everything with data.
I tried to use it, but could not manage, also on github search there is no simple/clean CLJS usage of portals
Yeah, then just store the state in :component-will-unmount
and restore it in :component-did-mount
. :)
Or maybe update the state on every change and use the state for the render. Then you don't need lifecycle methods at all.
Thanks for the info, I'll dig in more into portals. If I manage to accomplish, will update the thread
Is there a way to render an existing dom node as the main element of a reagent component?
element can be moved around the dom (ie instancing the component under another parent) and cannot be recreated
and preferably without a wrapper div, [:<>] yields a nil (dom-node)
Same way you'd do it in plain React, so I'd look for that. Also not the question above yours, one option there is using portals. Sounds like they can be useful here too.
isnt portal the opposite of this? ie adding react children to an existing node outside the component?
only thing I can find with plain react is dangerouslySetInnerHTML, which is also different, hrm
Portals are not adding children, they are rendering content from one instance inside another instance. Assuming the existing DOM node also comes from React, that's exactly what you need. If the DOM node is outside of React, then you can simply add it as a child to a DOM node managed by React. One huge problem - if the React instance is unmounted, that DOM node will also be lost.
yeah its outside react
I think I made another ugly hack that works:
(rc/create-class
{:component-did-mount
(fn [this]
(let [el (rd/dom-node this)]
(.. el -parentElement (replaceChild test-el el))))
:component-will-unmount
(fn [this]
(.. test-el -parentElement (replaceChild (rd/dom-node this) test-el)))
:reagent-render
(fn []
[:div])})
it wastes an extra <div> that's unused, but seems to fool react into hosting it without errors on unmount
That's pretty much the solution, yeah. Although I'd use refs insted of rd/dom-node
since it's deprecated.
ah for this im not worried about updating the react version, dom-node is much simpler than refs