reagent

Jérémie Pelletier 2024-03-02T14:49:39.485739Z

Is there a way to change the comparison operation of ratoms, without creating a custom implementation from scratch?

Jérémie Pelletier 2024-03-02T14:51:06.635289Z

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)

p-himik 2024-03-02T14:54:16.342239Z

Not possible. I would definitely reconsider the approach, even if it were possible.

Jérémie Pelletier 2024-03-02T15:06:16.213589Z

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

p-himik 2024-03-02T15:07:48.315889Z

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

Jérémie Pelletier 2024-03-02T15:08:07.705379Z

ah i don't mean globally change it, but only for a specific ratom

Jérémie Pelletier 2024-03-02T15:08:37.529599Z

kinda like react let you set the comparison function per-component, but in this case it happens at reagent's level

Jérémie Pelletier 2024-03-02T15:09:15.589579Z

the default is good in the general case, but not in custom domain specific ones

p-himik 2024-03-02T15:10:53.617519Z

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.

Jérémie Pelletier 2024-03-02T15:12:51.267159Z

ah yeah, this all happens before hitting react at all, doing it in components would duplicate the checks

Jérémie Pelletier 2024-03-02T15:13:24.591659Z

i had some success creating a custom ratom type, but it also requires copying private reagent implementation functions into app namespaces

p-himik 2024-03-02T15:16:18.210289Z

> 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?

Jérémie Pelletier 2024-03-02T15:17:58.020299Z

ratoms can be chained, not all resets and swaps get to react

p-himik 2024-03-02T15:22:41.396269Z

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.

Jérémie Pelletier 2024-03-02T15:26:02.193439Z

ah yeah i could look into that

Ertugrul Cetin 2024-03-02T17:34:15.314619Z

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]])

p-himik 2024-03-02T17:36:59.925369Z

If the only reason is to preserve the state of the <canvas> element, you can do that without preserving the React instance itself.

Ertugrul Cetin 2024-03-02T17:38:05.069789Z

> If the only reason is to preserve the state of the <canvas> elem Yes

p-himik 2024-03-02T17:38:22.445449Z

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.

Ertugrul Cetin 2024-03-02T17:40:09.301209Z

I tried to use it, but could not manage, also on github search there is no simple/clean CLJS usage of portals

p-himik 2024-03-02T17:41:40.288929Z

Yeah, then just store the state in :component-will-unmount and restore it in :component-did-mount. :)

p-himik 2024-03-02T17:42:21.799899Z

Or maybe update the state on every change and use the state for the render. Then you don't need lifecycle methods at all.

Ertugrul Cetin 2024-03-02T17:52:07.651239Z

Thanks for the info, I'll dig in more into portals. If I manage to accomplish, will update the thread

p-himik 2024-03-02T18:07:22.305859Z

Why do you want to avoid storing and restoring the data itself?

Ertugrul Cetin 2024-03-02T19:23:40.058009Z

It's not easy, canvas is webgl context

👍 1
Jérémie Pelletier 2024-03-02T23:18:07.744789Z

Is there a way to render an existing dom node as the main element of a reagent component?

Jérémie Pelletier 2024-03-02T23:18:56.346909Z

element can be moved around the dom (ie instancing the component under another parent) and cannot be recreated

Jérémie Pelletier 2024-03-02T23:19:29.965439Z

and preferably without a wrapper div, [:<>] yields a nil (dom-node)

p-himik 2024-03-02T23:19:50.540979Z

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.

Jérémie Pelletier 2024-03-02T23:20:54.516659Z

isnt portal the opposite of this? ie adding react children to an existing node outside the component?

Jérémie Pelletier 2024-03-02T23:22:08.342739Z

only thing I can find with plain react is dangerouslySetInnerHTML, which is also different, hrm

p-himik 2024-03-02T23:26:23.360289Z

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.

Jérémie Pelletier 2024-03-02T23:36:20.598979Z

yeah its outside react

Jérémie Pelletier 2024-03-02T23:37:08.708619Z

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])})

Jérémie Pelletier 2024-03-02T23:37:43.397709Z

it wastes an extra <div> that's unused, but seems to fool react into hosting it without errors on unmount

p-himik 2024-03-02T23:42:31.550059Z

That's pretty much the solution, yeah. Although I'd use refs insted of rd/dom-node since it's deprecated.

Jérémie Pelletier 2024-03-02T23:49:18.377499Z

ah for this im not worried about updating the react version, dom-node is much simpler than refs