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

createViewModel doesn't work correctly with setters for computed values #214

Closed
alex3683 opened this issue Sep 11, 2019 · 11 comments
Closed

Comments

@alex3683
Copy link

In my model I have several computed getters and accordingly setters, to derive the plain values from.

Simple example:

import { computed, observable } from 'mobx';

export default class Car {

  @observable public colorCode = 'red';

  @computed
  public get colorInstance(): any {
    return { colorCode: this.colorCode };
  }

  public set colorInstance(colorInstance: any) {
    this.colorCode = colorInstance.colorCode;
  }
}

If I now create a view model from it using createViewModel, changes applied to the colorCode property are directly visible in the view. If I instead apply changes by using the colorInstance setter, it seems to have no effect. See here for the full, running example: https://codesandbox.io/s/reverent-dew-pb6mh

When looking at the generated getters and setters in the code, the observation makes sense: computed values are always read from localComputedValues, while changes are always written to localValues. Hence, in my example colorInstance is written to the localValues colorInstance but read from localComputedValues, where it will never be up-to-date.

Is this a bug or is it intended to work like that and I made a mistake somewhere?

If you need further details, feel free to ask.

@alex3683 alex3683 changed the title createViewModel doesn't work correctly with setters for computed createViewModel doesn't work correctly with setters for computed values Sep 11, 2019
@urugator
Copy link
Contributor

urugator commented Sep 26, 2019

I think it's a bug, would the following help?

// https://github.com/mobxjs/mobx-utils/blob/1576286745c6229b34e1cf67353c3ccce1c6a843/src/create-view-model.ts#L56-L59
if (isComputedProp(model, key)) {  
  const modelComputedBox = _getAdministration(model, key) // Fixme: there is no clear api to get the derivation
  
  const get = modelComputedBox.derivation.bind(this);
  const set = modelComputedBox.setter 
     ? modelComputedBox.setter.bind(this) 
     : undefined;

  const localComputedBox = computed(get, { set });
      
  this.localComputedValues.set(key, localComputedBox);
}

// https://github.com/mobxjs/mobx-utils/blob/1576286745c6229b34e1cf67353c3ccce1c6a843/src/create-view-model.ts#L72-L78
set: action((value: any) => {
  if (isComputedProp(model, key)) {
     this.localComputedValues.get(key).set(value);
  } else if (value !== this.model[key as keyof T]) {
    this.localValues.set(key, value)
  } else {
    this.localValues.delete(key)
  }
})

@alex3683
Copy link
Author

@urugator
Jepp, that seems to fix the issue 👍🏼

@mweststrate
Copy link
Member

@alex3683 interested in making a PR with this fix, including a test?

@alex3683
Copy link
Author

@mweststrate Theoretically yes, but I guess I won't have the time to do this. I can try to do it, but I cannot promise any release date. Boss, wife and kids, all want me to do something else instead ;-)

@M-ZubairAhmed
Copy link

@alex3683 would you mind if i contribute to this one?

@urugator
Copy link
Contributor

@mweststrate btw note that the local computed ignores original computed's options (like equal), could also lead to some issues...

@alex3683
Copy link
Author

@M-ZubairAhmed Go ahead. I don't want to block this.

@mweststrate
Copy link
Member

@urugator, yeah there are an unlimited amount of potential issues with prototypes, getters, enumerability and view models.... This createViewModel is really a 'best default', and if it doesn't suffice, one should build their own view model by hand. Not entirely sure where to draw the line :).

So another solution would be to completely forbid the usage of getters / setters in view models....

@alex3683
Copy link
Author

So another solution would be to completely forbid the usage of getters / setters in view models....

Please don't. I use them a lot to transform string references into instances of other models and back. I think this is one of the greatest mobx features (including all the others ;-))

@ahoisl
Copy link
Contributor

ahoisl commented Dec 14, 2020

I fixed this issue independently in one of my projects, then saw this issue and now did go forward and merged my implementation with the proposed fix in this thread. See and please review the open PR.

Additionally, if one is interested in a "deep" view model, one that is also able to transparently work with nested objects and arrays, then I could go forward and try to merge my private implementation into the mobx-utils, too...

@NaridaL
Copy link
Collaborator

NaridaL commented Dec 16, 2020

Fixed by #286

@NaridaL NaridaL closed this as completed Dec 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants