Minor Changes
-
#936
6246a3c
Thanks @NullVoxPopuli! - Theuse
import fromember-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.
InTypeScript
, this still worked out, and the type ofdata
would be anumber
,
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 aReactive<number>
, which, like acell
, has a.current
property.
This is a readonly value -- howevercurrent
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@service
s.However, this has the same problems as
@service
-- in TypeScript, it requires you to usedeclare
and specify a type, which may or may not match the actual type ofStuckClock
.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, thethis
is actually the surrounding context aroundMyClass
, 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 )); }