-
Notifications
You must be signed in to change notification settings - Fork 75
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
Derived props not calculated before prop change events are fired? #180
Comments
Hmm, looking at the relevant code (https://github.com/AmpersandJS/ampersand-state/blob/master/ampersand-state.js#L405-L438) it looks like the order is that prop change events will fire before their related derived changes. Which kind of makes sense since all change events are synchronously fired, and we'd have to have the props themselves changing before we run the derived property updates. I'm not exactly sure how we could fix this from a quick look at the code :/ |
Well this is weird... you say that, but I just tried making a minimal test case and it seems the derived prop DOES get recalculated before the prop listener fires: var State = require('ampersand-state');
var Person = State.extend({
props: {
firstName: 'string',
lastName: 'string',
},
derived: {
fullName: {
deps: ['firstName', 'lastName'],
fn: function () {
return this.firstName + ' ' + this.lastName;
}
}
}
});
var me = new Person({firstName: 'John', lastName: 'Smith'});
me.on('change:firstName', function () {
console.log('full name is now ' + me.fullName);
});
me.firstName = 'James'; // "full name is now James Smith" (The above works on requirebin.com) But I've had bugs where this is not the case, and where I've had to use |
Ah, okay, I see the issue. The reason it's not failing in that situation is because the derived prop isn't in the cache, so when you call it for the first time from in that callback, it's running the function on the fly because it's not cached. If you add |
Ah ok that makes sense. So do you agree it's a problem? Is there any way the behaviour could be changed, by 'settling' all props (normal/session/derived) and THEN checking which ones have changed and firing all the change events? |
I sort of agree it's a problem :) I guess the first question is: if you want to read a derived prop from a change callback, why don't you listen to the derived prop instead? It's conceivable that we could try to batch updates like that, though my gut feeling is that it would be a pretty significant change: currently derived props are effectively just callbacks bound to the change events of their deps, so that would all have to change somehow to allow derived props to still work properly. I'm not sure of the implications their either for child model events etc Philip Roberts
|
yep I see what you mean, I'll try to give a convincing example... Say you've got a prop I guess you could argue that I should be watching only the exact properties I'm going to actually use (e.g. It feels weird that there's ever a time when I can read the derived props and they're temporarily 'wrong'.
Could this maybe work if there were two types of changes: |
I keep coming up against this problem in different places, I'm surprised it hasn't been raised before. Do you think this behaviour should be changed, given my extended example above? Or am I approaching derived props in the wrong way? |
@HenrikJoreteg thoughts? I'm not against the idea in principle, just unsure of the scale of work required/who has time to do it |
Not against this in principle either. I seem to recall there was some challenge that led it to be implemented this way. But I could certainly be wrong. |
Say I've got a prop
foo
, and a derived propbar
that depends onfoo
.If I listen to
change:foo
, and inside the listener I read the value ofbar
, I find that the value ofbar
is old, i.e. it has not updated to reflect the newfoo
value. But if I usesetTimeout(..., 0)
inside the listener to delay checking the value ofbar
till the next tick, then the value ofbar
is now up to date.Is this expected behaviour? I have a vague memory that ampersand-state is designed so that this shouldn't happen - that it always works out all derived props before firing any listeners. But my recent experience contradicts this. Or is it more likely something wrong with my code?
The text was updated successfully, but these errors were encountered: