Skip to content
Compare
Choose a tag to compare
@github-actions github-actions released this 10 Jul 00:26
· 387 commits to main since this release
9e5b8c0

Minor Changes

  • #936 6246a3c Thanks @NullVoxPopuli! - The use import from ember-resources now supports an alternate style of usage.
    This is partly to provide consistency across the different kinds of resources (and resource builders), whether or not arguments are provided.

    The motivation from this change comes from trying to better align with Starbeam's composition capabilities, and "define something once, use it anywhere" approach to that composition.

    For example, before, only this was possible:

    import { resource, use } from "ember-resources";
    
    const StuckClock = resource(() => 2);
    
    class MyClass {
      @use data = StuckClock;
    }
    
    new MyClass().data === 2;

    That looks a little awkward, because it looks like data is set to a constant.
    In TypeScript, this still worked out, and the type of data would be a number,
    but it still didn't look intuitive.

    Now, we can do this:

    import { resource, use } from "ember-resources";
    
    const StuckClock = resource(() => 2);
    
    class MyClass {
      data = use(this, StuckClock);
    }
    
    new MyClass().data.current === 2;

    The key difference here is that data is now a Reactive<number>, which, like a cell, has a .current property.
    This is a readonly value -- however current can still return a mutable data structure.

    This style of use ends up extending nicely to Resources that take arguments:

    import { tracked } from "@glimmer/tracking";
    import { resource, use, resourceFactory } from "ember-resources";
    
    const Clock = resourceFactory((locale) => resource(/* ... */));
    
    class MyClass {
      @tracked locale = "en-US";
    
      data = use(
        this,
        Clock(() => this.locale)
      );
    }

    Note

    The old way of using @use as a decorator is still supported, and has no plans of being deprecated.

    Another approach

    I can't recommend this approach for general usage, but it is supported under SemVer (for exploration and feedback).

    import { resource, use } from "ember-resources";
    
    const StuckClock = resource(() => 2);
    
    class MyClass {
      @use(StuckClock) declare data: number;
    }
    
    new MyClass().data === 2;

    This should feel familiar as it looks like what we're familiar with when it comes to declaring @tracked properties as well as @services.

    However, this has the same problems as @service -- in TypeScript, it requires you to use declare and specify a type, which may or may not match the actual type of StuckClock.

    Additionally, whenever we want to pass arguments to the resource, like this:

    import { tracked } from '@glimmer/tracking';
    import { resource, use } from 'ember-resources';
    
    const Clock = resourceFactory((locale) => resource( /* ... */);
    
    class MyClass {
      @tracked locale = 'en-US';
    
      @use(Clock(() => this.locale) declare data: number;
    }

    The arrow function passed to Clock would not have the correct this.
    This is confusing, because in every other situation where we use classes,
    the arrow function has the same context as the instance of the class.
    But due to how decorators are configured / transpiled, the this is actually the surrounding context around MyClass, because decorators are statically applied.

    class MyClass {
      @tracked locale = 'en-US';
    
      @use(Clock( static context here, not instance ) declare data: number;
    }

    So... that's why I want to recommend property = use(this, Foo) by default.

    class MyClass {
      @tracked locale = 'en-US';
    
      data = use(this, (Clock( instance access ));
    }