Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rdom]: updating state inside a $replace that no longer has it's parent #410

Open
maxsei opened this issue Sep 7, 2023 · 1 comment
Open

Comments

@maxsei
Copy link

maxsei commented Sep 7, 2023

It seems that continuously updating the state of a $replace component that has a $replace inside of it causes the inner $replace to get into an invalid state because the parent no longer exists. Is this intended behavior and/or misuse of rdom, or can this problem be solved within rdom itself?

import { defAtom } from "@thi.ng/atom";
import * as rx from "@thi.ng/rstream";
import * as tx from "@thi.ng/transducers";
import { ComponentLike } from "@thi.ng/rdom";
import { $compile, $replace } from "@thi.ng/rdom";

const root = document.getElementById("root");
if (!(root instanceof HTMLElement)) throw new Error("Root element not found");

const modal = defAtom<ComponentLike[]>([]);
const modalContainer = (body?: ComponentLike) =>
  body && [
    "div.absolute.absolute--fill.justify-center.items-center.flex.dn",
    { style: { "pointer-events": "none" } },
    body,
  ];

const window_of_5_random_numbers = ()=>rx
  .fromInterval(1000)
  .transform(
    tx.comp(
      tx.map(() => parseFloat(Math.random().toFixed(3))),
      tx.slidingWindow(5),
      tx.map((xx) => ["div", {}, xx.join(", ")]),
    ),
  )
  .subscribe(rx.trace("window_of_5_random_numbers"));

const rdom = $compile([
  "div.relative.vh-100",
  {},
  $replace(
    rx
      .fromAtom(modal)
      .subscribe(rx.trace("modal"))
      .map((x) => x[0])
      .map(modalContainer),
  ),
  [
    "button",
    {
      onclick: () => {
        modal.swap((prev) => [...prev, $replace(window_of_5_random_numbers())]);
      },
    },
    "Click Me to Push Random Numbers into the Modal",
  ],
  [
    "button",
    {
      onclick: () => {
        modal.swap((prev) => {
          prev.shift();
          return [...prev];
        });
      },
    },
    "click me to pop modal",
  ],
]);
rdom.mount(root);

After clicking the "Click Me to Push Random Numbers into the Modal" twice in a row

Uncaught (in promise) TypeError: this.parent is undefined
    mount sub.js:27
    mount compile.js:74
    update replace.js:60
    next sub.js:39
    add scheduler.js:41
    next sub.js:39
    dispatchTo subscription.js:219
    dispatch subscription.js:233
    dispatchXformVals subscription.js:267
    dispatchXform subscription.js:247
    next subscription.js:163
    dispatchTo subscription.js:219
    dispatch subscription.js:233
    dispatchXformVals subscription.js:267
    dispatchXform subscription.js:247
    next subscription.js:163
    dispatchTo subscription.js:219
    dispatch subscription.js:233
    next subscription.js:163
    dispatchTo subscription.js:219
    dispatch subscription.js:233
    next subscription.js:163
    fromAtom atom.js:44
    notifyWatches iwatch.js:25
    reset atom.js:37
    swap atom.js:47
    onclick main.ts:43
    setAttrib dom.js:275
    $attribs dom.js:261
    $el dom.js:130
    $treeTag dom.js:76
    $treeElem dom.js:58
    $tree dom.js:44
    mount compile.js:96
    mount compile.js:74
    <anonymous> main.ts:61
sub.js:27:8
@maxsei maxsei changed the title rdom: replacing a $replace inside a $replace [rdom]: replacing a $replace inside a $replace Sep 7, 2023
@maxsei maxsei changed the title [rdom]: replacing a $replace inside a $replace [rdom]: updating state inside a $replace that no longer has it's parent Sep 7, 2023
@maxsei
Copy link
Author

maxsei commented Sep 7, 2023

It turns out you can avoid this problem entirely by wrapping the componentlike's inside the modal atom with Fn0. Perhaps this issue could be moved to discussions?

import { defAtom } from "@thi.ng/atom";
import * as rx from "@thi.ng/rstream";
import * as tx from "@thi.ng/transducers";
import { ComponentLike } from "@thi.ng/rdom";
import { $compile, $replace } from "@thi.ng/rdom";
import { Fn0 } from "@thi.ng/api";

const root = document.getElementById("root");
if (!(root instanceof HTMLElement)) throw new Error("Root element not found");

const modal = defAtom<Fn0<ComponentLike>[]>([]);
const modalContainer = (body?: Fn0<ComponentLike>) =>
  body && [
    "div.absolute.absolute--fill.justify-center.items-center.flex.dn",
    { style: { "pointer-events": "none" } },
    body(),
  ];

const rdom = $compile([
  "div.relative.vh-100",
  {},
  $replace(
    rx
      .fromAtom(modal)
      .subscribe(rx.trace("modal"))
      .map((x) => modalContainer(x[0])),
  ),
  [
    "button",
    {
      onclick: () => {
        const window_of_5_random_numbers = rx
          .fromInterval(1000)
          .transform(
            tx.comp(
              tx.map(() => parseFloat(Math.random().toFixed(3))),
              tx.slidingWindow(5),
              tx.map((xx) => ["div", {}, xx.join(", ")]),
            ),
          )
          .subscribe(rx.trace("window_of_5_random_numbers"));
        const next = () => $replace(window_of_5_random_numbers);
        modal.swap((prev) => [...prev, next]);
      },
    },
    "Click Me to Push Random Numbers into the Modal",
  ],
  [
    "button",
    {
      onclick: () => {
        modal.swap((prev) => {
          prev.shift();
          return [...prev];
        });
      },
    },
    "click me to pop modal",
  ],
]);
rdom.mount(root);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant