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

What's difference between @computed decorator and getter function #161

Closed
boatkorachal opened this Issue Mar 15, 2016 · 10 comments

Comments

Projects
None yet
6 participants
@boatkorachal

boatkorachal commented Mar 15, 2016

I'm not sure when should i use the @computed decorator (without asStructure option) in class instead of the getter function for example

class Test {
    @observable firstName = 'first'
    @observable lastName = 'last'

    @computed
    get fullName () {
        return `${this.firstName} ${this.lastName}`
    }

    getFullName () {
        return `${this.firstName} ${this.lastName}`
    }
}

const test = new Test()
autorun(() => {
    console.log('computed:', test.fullName)
})

autorun(() => {
    console.log('getter:', test.getFullName())
})

test.firstName = 'salmon'
test.lastName = 'sushi'

// computed: first last
// getter: first last
// computed: salmon last
// getter: salmon last
// computed: salmon sushi
// getter: salmon sushi

Thanks

@OscarBarrett

This comment has been minimized.

Show comment
Hide comment
@OscarBarrett

OscarBarrett Mar 15, 2016

From the docs

use @computed if you want to reactively produce a new value that can be used by other observers

...

Computed properties can be optimized away in many cases by MobX as they are assumed to be pure. So they will not be invoked when there input parameters didn't modifiy or if they are not observed by some other computed value or autorun.

So if you're going to observe it, make it a computed property.

OscarBarrett commented Mar 15, 2016

From the docs

use @computed if you want to reactively produce a new value that can be used by other observers

...

Computed properties can be optimized away in many cases by MobX as they are assumed to be pure. So they will not be invoked when there input parameters didn't modifiy or if they are not observed by some other computed value or autorun.

So if you're going to observe it, make it a computed property.

@boatkorachal

This comment has been minimized.

Show comment
Hide comment
@boatkorachal

boatkorachal Mar 15, 2016

What I think is firstName and lastName is being observed in both computed and getter function. At first I thought the use case is for optimize as the docs said that the computed properties will not invoked when there input parameters didn't modify.

class Test {
    @observable firstName = 'first'
    @observable lastName = 'last'

    @computed
    get fullName () {
        return `${this.firstName} ${this.lastName}`
    }

    getFullName () {
        return `${this.firstName} ${this.lastName}`
    }
}

const test = new Test()
autorun(() => {
    console.log('computed:', test.fullName)
})

autorun(() => {
    console.log('getter:', test.getFullName())
})

test.firstName = 'salmon'
test.lastName = 'sushi'

test.firstName = 'salmon' // <---- again

// computed: first last
// getter: first last
// computed: salmon last
// getter: salmon last
// computed: salmon sushi
// getter: salmon sushi

But after I tried, the getter function didn't print duplicate fullName when I assign the firstName "salmon" again.

Thanks.

boatkorachal commented Mar 15, 2016

What I think is firstName and lastName is being observed in both computed and getter function. At first I thought the use case is for optimize as the docs said that the computed properties will not invoked when there input parameters didn't modify.

class Test {
    @observable firstName = 'first'
    @observable lastName = 'last'

    @computed
    get fullName () {
        return `${this.firstName} ${this.lastName}`
    }

    getFullName () {
        return `${this.firstName} ${this.lastName}`
    }
}

const test = new Test()
autorun(() => {
    console.log('computed:', test.fullName)
})

autorun(() => {
    console.log('getter:', test.getFullName())
})

test.firstName = 'salmon'
test.lastName = 'sushi'

test.firstName = 'salmon' // <---- again

// computed: first last
// getter: first last
// computed: salmon last
// getter: salmon last
// computed: salmon sushi
// getter: salmon sushi

But after I tried, the getter function didn't print duplicate fullName when I assign the firstName "salmon" again.

Thanks.

@mweststrate

This comment has been minimized.

Show comment
Hide comment
@mweststrate

mweststrate Mar 15, 2016

Member

Both solutions will exhibit the same behavior, but introducing @computed is better in the sense that it allows MobX to optimized it away more smartly.

If getFullName is not computed, and you change firstName, everyone using getFullName will recompute as well.

If, in contrast, @computed get fullName is used, the fullname is cached, so if the firstname is changed, the fullname is recomputed as well, but if the output of fullname doesn't change, nobody would be notified.

Also, if you read test.fullName somwhere, you will (usually) get a cached result back if decorated, while without decorator it would always be recomputed (which is the normal function behavior after all)

So, when in doubt, use it (if your function is pure in terms of depending only on observable values, which it should be)

Member

mweststrate commented Mar 15, 2016

Both solutions will exhibit the same behavior, but introducing @computed is better in the sense that it allows MobX to optimized it away more smartly.

If getFullName is not computed, and you change firstName, everyone using getFullName will recompute as well.

If, in contrast, @computed get fullName is used, the fullname is cached, so if the firstname is changed, the fullname is recomputed as well, but if the output of fullname doesn't change, nobody would be notified.

Also, if you read test.fullName somwhere, you will (usually) get a cached result back if decorated, while without decorator it would always be recomputed (which is the normal function behavior after all)

So, when in doubt, use it (if your function is pure in terms of depending only on observable values, which it should be)

@boatkorachal

This comment has been minimized.

Show comment
Hide comment
@boatkorachal

boatkorachal Mar 15, 2016

Got it! thank you very much :)

boatkorachal commented Mar 15, 2016

Got it! thank you very much :)

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Jul 25, 2017

@mweststrate so it seems there is not much difference between using a computed decorator and a simple getter? (besides optimization?)

ghost commented Jul 25, 2017

@mweststrate so it seems there is not much difference between using a computed decorator and a simple getter? (besides optimization?)

@mweststrate

This comment has been minimized.

Show comment
Hide comment
@mweststrate

mweststrate Jul 26, 2017

Member
Member

mweststrate commented Jul 26, 2017

@DmitryOlkhovoi

This comment has been minimized.

Show comment
Hide comment
@DmitryOlkhovoi

DmitryOlkhovoi Nov 26, 2017

nobody would be notified.

Who can be notified? I tried hard, and every time I get not a cached value. So I confused :)

@mweststrate

DmitryOlkhovoi commented Nov 26, 2017

nobody would be notified.

Who can be notified? I tried hard, and every time I get not a cached value. So I confused :)

@mweststrate

@windwalker

This comment has been minimized.

Show comment
Hide comment
@windwalker

windwalker Jan 4, 2018

@mweststrate

Also, if you read test.fullName somwhere, you will (usually) get a cached result back if decorated, while without decorator it would always be recomputed (which is the normal function behavior after all)

When would I get a cached result instead of getting the function recomputed? I tried the following example and it recomputes.

const {observable, computed} = mobx;

class Test {
    @observable firstName = 'first'
    @observable lastName = 'last'

    @computed
    get fullName () {
    	console.log('recompute fullname');
        return `${this.firstName} ${this.lastName}`
    }
}

let test = new Test()

console.log(test.fullName);
//recompute fullname
//first last

console.log(test.fullName);
//recompute fullname
//first last

windwalker commented Jan 4, 2018

@mweststrate

Also, if you read test.fullName somwhere, you will (usually) get a cached result back if decorated, while without decorator it would always be recomputed (which is the normal function behavior after all)

When would I get a cached result instead of getting the function recomputed? I tried the following example and it recomputes.

const {observable, computed} = mobx;

class Test {
    @observable firstName = 'first'
    @observable lastName = 'last'

    @computed
    get fullName () {
    	console.log('recompute fullname');
        return `${this.firstName} ${this.lastName}`
    }
}

let test = new Test()

console.log(test.fullName);
//recompute fullname
//first last

console.log(test.fullName);
//recompute fullname
//first last
@royriojas

This comment has been minimized.

Show comment
Hide comment
@royriojas

royriojas Jan 5, 2018

@windwalker I was confused by that too, but it seems values are cached when used inside a reaction, autorun or in the render of an observable React component.

Something like https://jsbin.com/rujuxe/edit?js,console,output you can see that the computed values are only called once even when we show then twice.

Also the value will be reevaluated if called directly. (check the click handler of the button)

@mweststrate are there any plans to also return a cached value from the normal usages outside of autorun, reaction and render?

royriojas commented Jan 5, 2018

@windwalker I was confused by that too, but it seems values are cached when used inside a reaction, autorun or in the render of an observable React component.

Something like https://jsbin.com/rujuxe/edit?js,console,output you can see that the computed values are only called once even when we show then twice.

Also the value will be reevaluated if called directly. (check the click handler of the button)

@mweststrate are there any plans to also return a cached value from the normal usages outside of autorun, reaction and render?

@mweststrate

This comment has been minimized.

Show comment
Hide comment
@mweststrate

mweststrate Jan 5, 2018

Member
Member

mweststrate commented Jan 5, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment