mobx-utils icon indicating copy to clipboard operation
mobx-utils copied to clipboard

A workaround to avoid cyclic references when using DeepObserve

Open aabuelenin opened this issue 4 years ago • 3 comments

I've a scenario where some business objects need to keep a reference to their parent, also, their parent could change in the runtime), for example:

class Root {
    @observable
    pages: Array<Page> = [];

    constructor() {
        deepObserve(this, (change, path, root) => {
            console.log(change);
            console.log(path);
            console.log(root);
        });
    }
}

class Page {
    @observable
    nodes: Array<Node> = [];
}

class Node {
    @observable.ref
    parentPage: Page;

    @action
    setPage(page: Page): void {
        this.parentPage = page;
    }
}

In this example Node references its parent causing a cyclic reference and a runtime error "The same observable object cannot appear twice in the same tree, trying to assign it to 'pages/0/nodes/0/parentPage', but it already exists at 'pages/0'"

I tried using observable.ref on parentPage hoping that deepObserve will treat parentPage as a reference, hence, it won't be considered a cyclic-reference, but it still failed.

Is there's a way to communicate to mobx that parentPage is just a reference and for the purposes of deepObserve, only the reference should be observed and not the page's members (the members of page would still be observable, but they won't be observed twice)?

aabuelenin avatar Aug 17 '20 20:08 aabuelenin

I realize this is an old issue, but as it hasn't been updated or addressed in over 2 years I think leaving another comment on it may help. I would also like a workaround for this. I've tried several different methods but ultimately I keep getting the same error thrown. In the code there's a comment saying that the check that throws this error is not actually necessary -- is there a way we could potentially disable it via an argument to the deepObserve() method?

@mweststrate @NaridaL (tagging you two b/c you have the highest contributor score in this repo, even though the repo development seems to have stagnated a little bit)

ToyWalrus avatar Mar 08 '23 22:03 ToyWalrus

The abovementioned error also happens for duplicate array entries:

const arr = observable.array()
deepObserve(arr, /* ... */)

// error; both arr[0] and arr[1] reference the same observable
arr[0] = arr[1]

// swapping items fails with the error too
[arr[0], arr[1]] = [arr[1], arr[0]]

This case is different since it doesn't form a cycle but rather a bifurcation. A single observable has two paths.

Is the error necessary in this case?

dangoodman avatar May 27 '23 08:05 dangoodman

Yes; it only supports trees. As soon as there are two paths to the root the events model would become ambiguous

On Sat, 27 May 2023, 10:38 dangoodman, @.***> wrote:

The abovementioned error also happens for duplicate array entries:

const arr = observable.array()deepObserve(arr, /* ... */) // error; both arr[0] and arr[1] reference the same observablearr[0] = arr[1] // swapping items fails with the error too[arr[0], arr[1]] = [arr[1], arr[0]]

This case is different since it doesn't form a cycle but rather a bifurcation. A single observable has two paths.

Is the error necessary in this case?

— Reply to this email directly, view it on GitHub https://github.com/mobxjs/mobx-utils/issues/275#issuecomment-1565279296, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAN4NBEZOVRHMXUPSPSBIV3XIG4SBANCNFSM4QCGADKQ . You are receiving this because you were mentioned.Message ID: @.***>

mweststrate avatar May 27 '23 08:05 mweststrate