Skip to content

onBecomeObserved is not called #4547

@Rulexec

Description

@Rulexec

Intended outcome:

I want to watch for observation of some property and do network requests when some other property allows it.

Actual outcome:

onBecomeObserved is not called, but I clearly accessing property in computed property.

How to reproduce the issue:

Code:

const events: string[] = [];

const item = makeAutoObservable({
  canLoad: false,
  value: undefined as number | undefined,
  error: undefined as Error | undefined,

  retry: () => {
    item.error = undefined;
    item.canLoad = true;
  },
});

let disposeReaction = noop;
onBecomeObserved(item, 'value', () => {
  events.push('valueBO');

  disposeReaction = reaction(
    () => item.canLoad,
    isCanLoad => {
      if (!isCanLoad) {
        return;
      }

      runInAction(() => {
        item.canLoad = false;
        item.value = 42;
      });
    },
    { fireImmediately: true },
  );
});
onBecomeUnobserved(item, 'value', () => {
  events.push('valueBU');
  disposeReaction();
});

const parentItem = makeAutoObservable({
  get hasError() {
    return Boolean(item.error);
  },
  get isLoading() {
    return item.value === undefined;
  },
});

const andAnotherItem = makeAutoObservable({
  get see() {
    if (parentItem.hasError) {
      events.push('seenError');
    } else if (parentItem.isLoading) {
      events.push('seenLoading');
    } else {
      events.push(`seenValue ${item.value}`);
    }

    return undefined;
  },
});

autorun(() => {
  void andAnotherItem.see;
});

await sleep(0);
runInAction(() => {
  item.error = new Error();
});

await sleep(0);
runInAction(() => {
  item.retry();
  void parentItem.isLoading;
  when(() => !parentItem.isLoading);
});

await sleep(50);

expect(events).toStrictEqual([
  'valueBO',
  'seenLoading',
  'seenError',
  'valueBU',
  'seenLoading',
  'valueBO',
  'seenValue 42',
]);

It gives following error:

- Expected  - 2
+ Received  + 0

@@ -2,8 +2,6 @@
    "valueBO",
    "seenLoading",
    "seenError",
    "valueBU",
    "seenLoading",
-   "valueBO",
-   "seenValue 42",

seenLoading indicates, that autorun is accessing parentItem.isLoading, but valueBO is not called.

Then cryptic magic (for me, at least) happens:

  • Commenting void parentItem.isLoading inside action fixes issue
  • Commenting when(() => !parentItem.isLoading) inside action fixes issue (but we are leaving void ..., so only one of this lines can exist)
  • Commenting disposeReaction() inside onBecomeUnobserved fixes issue

Versions

"mobx": "6.13.7",

Thanks

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions