NullVoxPopuli / ember-deep-tracked

Deep auto-tracking for when you just don't care, and want things to work (at the cost of performance in some situtations)
MIT License
30 stars 5 forks source link

Issues with accessing the store from a deep-tracked object #188

Open spuxx1701 opened 3 years ago

spuxx1701 commented 3 years ago

There is an issue with accessing the ember-data store from an object if that object is being kept in a deep-tracked array. A minimal example to reproduce the behavior can be found here: https://github.com/LeopoldHock/ember-deep-tracked-test

The core issue

Say we have a custom object that can make use of service injection by having its owner set in the constructor method.

export default class Car {
    @service store;

    constructor(owner) {
        setOwner(this, owner);
    }
}

And after instantiation, that object will be put into a nested deep-tracked context.

// e.g. in a service
import { tracked } from 'ember-deep-tracked';
@tracked data = {
    cars = []
}
let car = new Car(this);
data.cars.push(car);

And at some point, that object attempts to access the injected store to find a record.

// in car.js
let someRecord = this.store.peekRecord("my-collection", "some-key");

someRecord will be null, while requesting the same record in a different contect (e.g. a service) will return the record. The issue does not occur in a non-tracked context (e.g. by simply removing @tracked).

Alonski commented 3 years ago

I think that this isn't necessarily a bug but an incorrect usage of tracked. From my understand what happens when @tracked isn't applied is this:

  1. An object is created and is then "autotracked" by Ember (Not 100% sure of this) in some way might be something else.
  2. When a function is called on a car the function retains the calling context.
  3. Thus the store in changeColor is the correct store and not a Proxy of the store.

When calling with @tracked we get this:

  1. An object is created and tracked outside of Ember (Not 100% sure of this).
  2. When a function is called on a car the function does not retain the calling context.
  3. Thus the store in changeColor is now not the correct store. It is now a Proxy of the store (Not sure why).

Decorating changeColor with @action forces Ember to maintain the context correctly: https://github.com/Alonski/ember-deep-tracked-test/commit/7a2f0174d38d0f39d32626f8953c4305759416c3

And not sure if this will work but: https://alonski-leopoldhock-ember-deep-tracked-test-g4xjjvpcwgrv.github.dev/

spuxx1701 commented 3 years ago

I'd argue that getting a "different" version of a singleton is not expected behavior when injecting a service, so I'd definitely consider this a bug. I'll also add that simply switching to https://github.com/tracked-tools/tracked-built-ins for tracking the object will result in the expected behavior - fully functional tracking and access to the "correct" store.

However, using @action is at least a good workaround. I didn't think of that!

/ Can you elaborate on the last point? 3. Thus the store in changeColor is now not the correct store. It is now a Proxy of the store (Not sure why). What woud that Proxy be used for? In what situation would it be desirable to get a proxy of the store, not the actual store?

Alonski commented 3 years ago

@NullVoxPopuli I am having a hard time figuring out how to recreate this issue in a Unit test. Would like help please :)

NullVoxPopuli commented 3 years ago

Where did you get stuck? What code have you tried so far?