Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initialize is sometimes called before initial attributes have been set #237

Open
janpaul123 opened this issue Apr 6, 2016 · 2 comments
Open

Comments

@janpaul123
Copy link
Contributor

It seems a reasonable assumption/invariant that when initialize is called, the initial attributes have been set, and this is in fact true most of the time. However, it is not always true, because when the State is used as a child of a different State, then it is initialised with empty attributes (which will trigger initialize, and only then is set called on it with the initial attributes — but with silent: true, so you cannot listen for this to happen in initialize.

So, concrete example. I have a derived property that is expensive to calculate, so I don't want it to be a derived property, but something that I manually update (perhaps throttled or so). But I do want it to be immediately available for the initial data and not trigger a change event initially (to keep the behaviour consistent with how derived properties work), so I write this:

initialize() {
    // Initially calculate but suppress events, to keep behaviour
    // consistent with derived properties
    this.set({ expensiveProperty: this._calculateExpensiveProperty() }, 
      { silent: true, initial: true });

    // After that throttle updates to this property
    this.listenTo(this, 'change:myDependency', _.throttle(() => 
      this.expensiveProperty = this._calculateExpensiveProperty(), 1000));
},

Now this works fine in most cases, except when this State is used in children of another State. The only workaround I currently see is to actually make a "dummy" derived property and do all this there (and make sure it only gets called once through some boolean or something).

@janpaul123
Copy link
Contributor Author

Actually, the workaround that I suggested (a "dummy" derived property), doesn't work because derived properties behave lazily for initial data (though they are updated non-lazily on change events that have not been silenced). I don't see convenient workarounds then.

@janpaul123
Copy link
Contributor Author

This is the best workaround I could come up with:

initialize() {
    this.listenTo(this, 'change:myDependency', _.throttle(() => 
      this.expensiveProperty = this._calculateExpensiveProperty(), 1000));
},

set(...args) {
    Model.prototype.set.apply(this, args);

    const options = args[args.length - 1];
    if (options.initial) {
      this.set({ expensiveProperty: this._calculateExpensiveProperty() }, 
        { silent: true });
    }

    return this;
},

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant