I'd like to define stores where observables are only mutated by actions and cannot be mutated externally of the store. This currently is not possible because the code generator defines get/set properties for observables. It would be particularly useful to define read-only observable ObservableList
I know one option is to make private observables then provide read-only computed properties for the observables, but a) that seems unnecessarily verbose, and b) it's not really computed, they're just simple accessors.
For comparison, here's a simple example of how it currently works.
# Current approach
class _TestStore with Store {
@observable
int value;
}
# Current generated code
mixin _$TestStore on _TestStore, Store {
final _$valueAtom = Atom(name: '_TestStore.value');
@override
int get value {
_$valueAtom.context.enforceReadPolicy(_$valueAtom);
_$valueAtom.reportObserved();
return super.value;
}
@override
set value(int value) {
_$valueAtom.context.conditionallyRunInAction(() {
super.value = value;
_$valueAtom.reportChanged();
}, _$valueAtom, name: '${_$valueAtom.name}_set');
}
}
Here's one suggestion of an alternate approach.
# Alternate approach
class _TestStore with Store {
int _value;
@observable(setter: '_setValue')
int get value
=> _value;
void _setValue(int value)
=> _value = value;
}
# Alternate generated code
mixin _$TestStore on _TestStore, Store {
final _$valueAtom = Atom(name: '_TestStore.value');
@override
int get value {
_$valueAtom.context.enforceReadPolicy(_$valueAtom);
_$valueAtom.reportObserved();
return super.value;
}
@override
void _setValue(int value) {
# Same code that was originally in the generated setter
_$valueAtom.context.conditionallyRunInAction(() {
super.value = value;
_$valueAtom.reportChanged();
}, _$valueAtom, name: '${_$valueAtom.name}_set');
}
}
I think the ObservableList
Are you suggesting something like a @readonly annotation where a setter won't be generated:
@readonly
@observable
int value;
@pavanpodila I don't think so. If no code at all is generated for a setter then how could value be mutated such that this code would run and trigger a change?
```
_$valueAtom.context.conditionallyRunInAction(() {
super.value = value;
_$valueAtom.reportChanged();
}, _$valueAtom, name: '${_$valueAtom.name}_set');
````
Ok got it! This will be a custom setter then, whose name you are specifying in the annotation
Yes, that's what I was suggesting. There may be a better way to declare a readonly observable that can be mutated within the store, that approach was the one I thought was simplest though.
Can't you do this right now by creating an observable on a private field?
class _TestStore with Store {
@observable(setter: '_setValue')
int _value = 0;
int get value => _value;
@action
void incrementValue() => _value++;
}
@shyndman that seems to work for me, you don't need the setter param though (it doesn't exist)
class _TestStore with Store {
@observable
int _value = 0;
int get value => _value;
@action
void incrementValue() => _value++;
}
It would be cool if @readonly generated the public getter, and you only needed to write
class _TestStore with Store {
@readonly
@observable
int _value = 0;
@action
void incrementValue() => _value++;
}
Or even better
class _TestStore with Store {
@observable(readonly: true)
int _value = 0;
@action
void incrementValue() => _value++;
}
Adding a @readonly annotation would be great, meaning a public getter and a private setter are generated, so the value is observable and only mutable from inside the store.
If this feature is really desirable, I suggest we upvote the issue. That way we can prioritize on what we pick up next.
@eltonomicon what your thoughts about the ObservableList, I see that this approach is good for simple values, link string or int, but for a complex class, that expose methods that allow changing of itself, how do you think that we could still user ObservableList but only with inside store modifications.
@AlbertoMonteiro you can that complex class be a Store itself. I do this in a bunch of places today.
Sorry @MisterJimson but I think that you didn't understand what I said.
Most helpful comment
It would be cool if
@readonlygenerated the public getter, and you only needed to writeOr even better