NullVoxPopuli / ember-resources

An implementation of Resources. Supports ember 3.28+

Home Page:https://github.com/NullVoxPopuli/ember-resources/blob/main/docs/docs/README.md

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`modify` is not called if the resource isn't accessed

swastik opened this issue · comments

We're on an older version (4.x.x) of ember-resources and we have the newer styled resources, i.e. imported from ember-resources/core.

We want to trigger a task on this resource from outside, when a textarea gets focused. That task sets some internal state—the idea being that when our args change, we can cancel the task and reset all state.

So the full code is something like this:

Resource
import { Resource } from 'ember-resources/core';

interface HistoryApiArgs {
  id: number;
}

export default class HistoryApi extends Resource<Named<HistoryApiArgs>> {
  private lastId?: number;

  constructor(owner: unknown) {
    super(owner);
    registerDestructor(this, this.teardown);
  }

  modify(_: never, args: HistoryApiArgs) {
    if (this.lastId !== args.id) {
      this.teardown();
    }

    this.lastId = args.id;
  }

  @action private teardown() {
    taskFor(this.loadHistoryTask).cancelAll();
  }

  @restartableTask
  *loadHistoryTask() {
    try {
      // fetch things
      // return a value
    } catch (error) {
      captureException(error);
      throw error;
    }
  }
}

The id in args here is a tracked property. The caller looks like this:

Component
private historyApi = HistoryApi.from(this, () => {
  return {
    itemId: this.args.item.id,
  };
});

@action async loadHistory() {
  try {
    let history = this.historyApi.loadHistoryTask.perform();
    // do something with this
  } catch (err) {
    console.log(err)
  }
}

My expectation is that when this task is performed, if args.itemId changes, modify will be called again, without "consuming" the resource again. However, I'm not seeing modify hook called at all, after the first time that is!

I get that this sort of usage is outside ember-resource's recommended usage, and we have refactored this a bit to be more aligned with the recommended usage, but the modify not being called at all when args change stumped me a bit. I'm wondering if it's intended that the modify hook isn't called at all when args change here—thoughts?

I'm wondering if it's intended that the modify hook isn't called at all when args change here—thoughts?

yes! this is because there is no reactive bit pulling on the resource. This pulling on data is what makes tracking and resources (in most cases ;) ) all automatic.

Since async loadHistory() is "just a function call", not tied to any reactive-context, or used as part of a derived data something downstream, the auto-tracking behavior you're expecting is opted-out of.

Since you are wanting to reset state when a task is restarted, (without more details anyway), you could change all your state to instead be derived data, and not worry about "updates" at all.

Hope this helps, and please let me know anything isn't clear!

That makes sense, thank you!

Since async loadHistory() is "just a function call", not tied to any reactive-context, or used as part of a derived data something downstream, the auto-tracking behavior you're expecting is opted-out of.

I was thinking because that function calls this.historyApi.loadHistoryTask.perform(); which is a task on the resource that:

  • the resource is initialised, modify called (which it is),
  • and that ties it in with autotracking, since it's accessing args.id and args.id is autotracked. So whenargs.id changes, modify is called again (which it is not)

Is my understanding incorrect?

Is my understanding incorrect?

unfortunately, yes <3

Your logic is reasonable though!

The key missing piece is that auto-tracking doesn't go in to effect unless the template pulls on data.

(aka, "if you don't render a thing, does the thing need to exist?")

Perfect, that makes sense! I'll close this issue now!