Whats the difference between #observable and #observable.ref modifiers in mobx? - javascript

Mobx supports both #observable and #observable.ref modifiers and their official doc says
observable: This is the default modifier, used by any observable. It clones and converts any (not yet observable) array, Map or plain object into it's observable counterpart upon assignment to the given property
observable.ref: Disables automatic observable conversion, just creates an observable reference instead.
I do not understand why would we need to create a observable reference for an already existing observable. How are these two different and what are their use cases ?

observable.ref will only track reference changes to the object, which means that you will need to change the whole object in order to trigger the reaction. So if you, for example, have an observable array that is tracked by reference, the contents of the array will not be tracked. Also if you add items to the array that change will also not be tracked.
import { observable, reaction } from "mobx";
const test = observable(
{
reference: [{ id: 1 }]
},
{
reference: observable.ref
}
);
reaction(
() => {
return test.reference.length;
},
() => {
console.log("Reaction 1: reference length changed");
}
);
reaction(
() => {
return test.reference[0];
},
() => {
console.log("Reaction 2: reference item changed");
}
);
test.reference[0] = { id: 2 }; // this will not trigger the reactions
test.reference.push({ id: 3 }); // this will not trigger the reactions
test.reference.pop(); // this will not trigger the reactions
test.reference = []; // this will trigger both reactions
code sandbox example

I'd like to explain the Ivan V.'s answer.
In his code, test.reference is a reference which will not change the address of the variable in the memory until reassign.
operations like push/pop or edit the value of test.reference[0] just change the value instead of the variable's reference.
So when using the #observable.ref, mobx will compare the memory address of the variable which is observed.But when using the #observable, mobx will compare the variable's value to decide to trigger the reactions.

Related

Why using toRef(props) and is it good idea to change their value in CompositionAPI?

I've seen a pattern of using props in of CompositionAPI very often,
that is use toRefs to make all entries of props ref.
I'm kind of confused by it.
For exmaple, from the Vue 3 official guide:
export default {
props: {
user: {
type: String,
required: true
}
},
setup(props) {
const { user } = toRefs(props)
//... use user's value
}
}
I have 2 questions in 2 scenearios:
when the props.user is already reactive
Its value will change if it's changed in any ancestors, so why we need to use toRefs? Doesn't it already reactive?
if it's not reactive, it's just a primitive string value
Does making it reactive means we're going to change its value?
I think making a object reactive also imply that its value is welcomed to be changed.
But all the guides and linters warn us that we'd better not to change the props value.(for not writing to the computed value or something)
If I can change the props value directly in the component, I no longer need to emit the changes to parent component everytime.
It's very convenient but I don't know whenther it is a good idea to change the props value after we're sure it becomes reactive?
Since props aren't supposed to be mutated, this is useful for a specific case that is explained in the documentation; a ref that is computed from a prop needs to be passed as an argument:
const { user } = toRefs(props)
// or
// const user = computed(() => props.user)
someFunction(user);
Where a function makes use of composition API or just needs an argument to be passed by reference rather than by value due to the way it works, e.g.:
function someFunction(val) {
setTimeout(() => {
console.log('Up-to-date value:', unref(val));
}, 1000);
}

How can I make an Ember computed property depend on all descendent properties of a variable?

I'm trying to create a computed property that I want to be reevaluated whenever any value in a deeply nested object changes. I understand that myObj.[] can be used to reevaluate computed properties whenever any object in an array changes, but I want this to be recursive.
eg I have
// should recalculate whenever myObj.x.y.z changes, or when myObj.a.b.c changes
computed('myObj', function() {
// ...
})
I don't know in advance exactly how the object is structured, and it may be arbitrarily deep.
Neither computed('myObj.[]', ...) nor computed('myObj.#each', ...) seem to work for this.
Any ideas how to do this?
In Ember it is possible to define computed properties at runtime
import { defineProperty, computed } from '#ember/object';
// define a computed property
defineProperty(myObj, 'nameOfComputed', computed('firstName', 'lastName', function() {
return this.firstName+' '+this.lastName;
}));
So taking that a step further, you could dynamically create whatever computed property key string you want at runtime (this could be in component's init() or something):
// define a computed property
let object = {
foo: 'foo',
bar: 'bar'
}
this.set('myObj', object);
let keys = Object.keys(object).map((key) => {
return `myObj.${key}`
});
defineProperty(this, 'someComputed', computed.apply(this, [...keys, function() {
// do something here
}]));
It's up to you to figure out how to properly recursively traverse your objects for all the dependent keys without creating cycles or accessing prototype keys you don't want...or to consider whether or not this is even that good of an idea. Alternatively, you could try to handle the setting of these properties in such a way that retriggers a computation (which would be more in line with DDAU). I can only speculate from what you've provided what works but it's certainly possible to do what you want. See this twiddle in action
could you try anyone computed/obeserver like below..
But try to prefer the computed.
import { observer } from '#ember/object';
import EmberObject, { computed } from '#ember/object';
partOfNameChanged1: observer('myObj','myObj.[]','myObj.#each', function() {
return 'myObj is changed by obeserver';
})
partOfNameChanged2: computed ('myObj','myObj.[]','myObj.#each', function() {
return 'myObj is changed by computed';
})
then in your handlebar/template file
{{log 'partOfNameChanged1 is occured' partOfNameChanged1}}
{{log 'partOfNameChanged2 is occured' partOfNameChanged2}}
Then you have to associate/assign this partOfNameChanged1 / partOfNameChanged2 to some where in the handlebar or to any other variable in your .js file.
As long as you have not assigned this computed/observer property partOfNameChanged1 /partOfNameChanged2 to somewhere, then you will not get it's value.

Deep autorun on MobX array of objects

I've looked at this issue on Github and this question on stackoverflow but am still unsure how to trigger an autorun for the data structure I have. I get the data from storage as a json object.
// Object keys do not change
const sampleData =
[
{
"title": "some-title",
"isActive": true,
"isCaseSensitive": false,
"hidePref": "overlay",
"tags": ["tag1", "tag2"]
},
{
"title": "all-posts",
"isActive": false,
"isCaseSensitive": true,
"hidePref": "overlay",
"tags": ["a", "b", "c"]
}
];
class Store {
#observable data;
constructor() {
this.data = getDataFromStorage();
if (this.data === null) {
this.data = sampleData;
}
}
}
const MainStore = new Store();
autorun(() => {
console.log("autorun");
sendPayloadToAnotherScript(MainStore.data);
})
How do I get autorun to run every time a new object is added to the data array, or any of the field values in the objects are changed?
The easiest way to get this working is to use JSON.stringify() to observe all properties recursively:
autorun(() => {
console.log("autorun");
// This will access all properties recursively.
const json = JSON.stringify(MainStore.data);
sendPayloadToAnotherScript(MainStore.data);
});
Mobx-State-Tree getSnapshot also works. And even though I can't find it right now: I read that getSnapshot is super-fast.
import { getSnapshot } from 'mobx-state-tree'
autorun(() => {
console.log("autorun");
// This will access all properties recursively.
getSnapshot(MainStore.data);
sendPayloadToAnotherScript(MainStore.data);
});
JSON.stringify() or getSnapshot() is not the right way to do it. Because that has a big cost.
Too Long => First part explains and shows the right way to do it. After it, there is also the section that shows how the tracking and triggering work through objects and arrays observables. If in a hurry Make sure to skim. And to check those sections: Track arrays like a hero show direct examples that work well. Code Illustration speaks better shows what works and what doesn't. Know that the starting explanation clear all. The last section is for the depth people who want to get a slight idea about how mobx manages the magic.
From the documentation you can read how reactivity work. What autorun() or reaction() react to and trigger.
https://mobx.js.org/understanding-reactivity.html
To resume it:
Object or arrays. Will make an autorun react if you make an access to it. mobx track accesses and not changes
That's why if you do
autorun(() => {
console.log(someObservable)
})
it wouldn't react on a change on the someObservable.
Now the confusing thing for people. Is ok but I'm making an access on the observable that holds the array property (in the question example that's MainStore object). And that should make it trackable (MainStore.data is being tracked.).
And yes it is
However. For a change to trigger a reaction. That change should come from an assignment or mutation that is tracked by the observable proxy. In arrays that would be a push, splice, assignment to an element by index and in objects that only can be an assignment to a prop value.
And because our observable that holds the array is an object. So to have a change for the array property to trigger the reaction through that object observable it needs to come from an assignment store.myArray = [].
And we don't want to do that. As a push is more performing.
For this reason. U need to rather make the change on your array. Which is an observable. And to track your array rather than the prop of the object. You have to make access in the array. You can do that through array.length or array[index] where index < length a requirement (because mobx doesn't track indexes above the length).
Note that:
observableObject.array = [...observableObject.array, some] or observableObject.array = observableObject.array.slice() //... (MainStore.data when making change. Instead of MainStore.data.push(). MainStore.data = [...MainStore.data, newEl]) would work and trigger the reaction. However using push would be better. And for that better we track the array. And so
Track arrays like a hero (.length)
autorun(() => {
console.log("autorun");
// tracking
MainStore.data.length
// effect
sendPayloadToAnotherScript(MainStore.data);
})
// or to make it cleaner we can use a reaction
reaction(
() => [MainStore.data.length], // we set what we track through a first callback that make the access to the things to be tracked
() => {
sendPayloadToAnotherScript(MainStore.data);
}
)
A reaction is just like an autorun. With the granulity of having the first expression that allow us to manage the access and what need to be tracked.
All is coming from the doc. I'm trying to explain better.
Code Illustration speaks better
To illustrate the above better let me show that through examples (both that works and doesn't work):
Note: autorun will run once a first time even without any tracking. When we are referring to NOT trigger reaction is talking about when change happen. And trigger at that point.
Array observable
const a = observable([1, 2, 3, 4])
reaction(
() => a[0], // 1- a correct index access. => Proxy get() => trackable
() => {
console.log('Reaction effect .......')
// 3- reaction will trigger
}
)
a.push(5) // 2- reaction will trigger a[0] is an access
const a = observable([1, 2, 3, 4])
reaction(
() => a.length, // 1- a correct length access. => Proxy get() => trackable
() => {
console.log('Reaction effect .......')
// 3- reaction will trigger
}
)
a.push(5) // 2- reaction will trigger a.length is a trackable access
const a = observable([1, 2, 3, 4])
reaction(
() => a.push, // an Access but. => Proxy get() => not trackable
() => {
console.log('Reaction effect .......')
// reaction will NOT trigger
}
)
a.push(5) // reaction will NOT trigger a.push is not a trackable access
Object observable
const o = observable({ some: 'some' })
autorun(() => {
const some = o.some // o.some prop access ==> Proxy get() => trackable
console.log('Autorun effect .........')
})
o.some = 'newSome' // assignment => trigger reaction (because o.some is tracked because of the access in autorun)
const o = observable({ some: 'some' })
autorun(() => {
const somethingElse = o.somethingElse // access different property: `somethingElse` prop is tracked. But not `some` prop
console.log('Autorun effect .........')
})
o.some = 'newSome' // assignment => reaction DOESN'T run (some is not accessed so not tracked)
const o = observable({ some: 'some' })
autorun(() => {
console.log(o) // NO ACCESS
console.log('Autorun effect .........')
})
o.some = 'newSome' // assignment => reaction DOESN'T Run (No access was made in the reaction)
let o = observable({ some: 'some' })
autorun(() => {
const some = o.some // Access to `some` prop
console.log('Autorun effect .........')
})
o = {} // assignment to a variable => reaction DOESN'T Run (we just replaced an observable with a new native object. No proxy handler will run here. yes it is stupid but I liked to include it. To bring it up. As we may or some may forget themselves)
Object observables with arrays observables as props
const o = observable({ array: [0,1,2,3] }) // observable automatically make
// every prop an observable by default. transforming an Arry to an ObservableArray
autorun(() => {
const arr = o.array // tracking the array prop on the object `o` observable
console.log('Autorun effect .........')
})
o.array.push(5) // will NOT trigger the rection (because push will trigger on the array observable. Which we didn't set to be tracked. But only the array prop on the o Observable)
o.array = [...o.array, 5] // assignment + ref change => Will trigger the reaction (Assignment to a prop that is being tracked on an object)
o.array = o.array.slice() // assignment + ref change => Will trigger the reaction (Assignment to a prop that is being tracked on an object)
o.array = o.array // Assignment => But DOESN'T RUN the reaction !!!!!!!!!
// the reference doesn't change. Then it doesn't count as a change !!!!!
const o = observable({ array: [0,1,2,3] })
autorun(() => {
const arr = o.array // tracking the array prop on the object `o` observable
const length = o.array.length // We made the access to .length so the array observable is trackable now for this reaction
console.log('Autorun effect .........')
})
o.array.push(5) // will trigger reaction (array is already tracked .length)
o.array = [...o.array, 5] // assignment => Will trigger the reaction too (Assignment to a prop that is being tracked on an object)
// Push however is more performing (No copy unless the array needs to resize)
With that, you have a great perception. Normally the whole cases are well covered.
What about with react-rerendering
The same principle apply with observer() higher order component factory. And the how the tracking happen within the render function of the component.
Here some great examples from an answer I wrote for another question
https://stackoverflow.com/a/73572516/7668448
There is code examples and playgrounds too where u can easily test for yourself on the fly.
How the tracking and the triggering happen
Observables are proxy objects. By making an access to a prop => we trigger the proxy methods that handle that operation. store.data will trigger the get() method of the proxy handler. And at that handler method. The tracking code run and that way mobx can follow all accesses. Same thing for store.data = []. That would trigger the set() method of the handler. Same for store.data[0] = 'some', however this would happen at the store.data proxy object (array observable) rather then the store itself. store.data.push() would trigger the get() method of the proxy. And then it would run the condition that check that it's push prop.
new Proxy(array, {
get(target, prop, receiver) {
if (prop === 'push') {
// handle push related action here
return
}
// ....
// handle access tracking action here
}
set(obj, prop, value) {
// if prop was an observable make sure the new value would be too
// Don't know how mobx does it. Didn't take the time to check the code
if (isObservable(obj[prop]) && !isObservable(value)) {
value = observable(value)
}
obj[prop] = value
// handle assignment change neededactions
}
})
Actually, I got a bit curious. And went and checked the actual mobx implementation. And here are some details:
For the arrayObservable here are the details:
The proxy handler are defined in arrayTraps
src/types/observablearray.ts#L84
We can see every target (element that was made an observable). Have a $mobx property that have an
As shown here src/types/observablearray.ts#L86
$mobx if curious it's just a Symbol export const $mobx = Symbol("mobx administration")src/core/atom.ts#L17
And you can see how the administration object is used to handle all. That handle the actions and magic of tracking.
const arrayTraps = {
get(target, name) {
const adm: ObservableArrayAdministration = target[$mobx]
if (name === $mobx) {
// if $mobx (requiring the administration) just forward it
return adm
}
if (name === "length") {
// if length ==> handle it through administration
return adm.getArrayLength_()
}
if (typeof name === "string" && !isNaN(name as any)) {
// all proxy names are strings.
// Check that it is an index. If so handle it through the administration
return adm.get_(parseInt(name))
}
// Up to now ==> if $mobx, length or 0, 1, 2 ....
// it would be handled and for the two later through administration
if (hasProp(arrayExtensions, name)) {
// If it's one of the extension function. Handle it through
// the arrayExtensions handlers. Some do extra actions like
// triggering the process of handling reactions. Some doesn't
return arrayExtensions[name]
}
// if none of the above. Just let the native array handling go
return target[name]
},
set(target, name, value): boolean {
const adm: ObservableArrayAdministration = target[$mobx]
if (name === "length") {
// Handle length through administration
adm.setArrayLength_(value)
}
if (typeof name === "symbol" || isNaN(name)) {
target[name] = value
} else {
// numeric string
// handle numeric string assignment through administration as well
adm.set_(parseInt(name), value)
}
return true
},
preventExtensions() {
die(15)
}
}
Through arrayExtensions. There is those that are handled through the same simpleFunc.
src/types/observablearray.ts#L513
And you can see how calling such calls and through the proxy (get handler). Those calls signal that the observable is being observed and the dehancedValues are managed that are recovered from the administration object. src/types/observablearray.ts#L545
For the other arrayExtensions that have special handling like push we can see how it's triggering the process of signaling change. src/types/observablearray.ts#L457
First we can see that push is using splice handling of the administration. Making push and splice to be handled by the same handler. reusability
You can check this part that seems to be the part for push or splice that trigger and handle interceptors src/types/observablearray.ts#L238
Interceptors as by doc ref
For change notification and reaction triggering this code here
src/types/observablearray.ts#L261 does that handling. You can see it through this line src/types/observablearray.ts#L337
this.atom_.reportChanged()
// conform: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/observe
if (notify) {
notifyListeners(this, change)
}
src/types/observablearray.ts#L256 show how the length is tracked and used and it check if the internal array is modified. To show that mobx does track many things. Or does check.
If you are more curious. You can dig further. But through the above you can already have a good idea how mobx manage it's magic. And understanding how mobx track (still not fully in depth) and also how the observable that are proxies and how proxies works. All that help well.
Here extra links:
packages/mobx/src/types/observablearray.ts
packages/mobx/src/types/observableobject.ts
packages/mobx/src/types/dynamicobject.ts
packages/mobx/src/types/observablemap.ts
packages/mobx/src/types/observableset.ts
packages/mobx/src/types/observablevalue.ts
packages/mobx/src/utils/utils.ts
If you check those links. You would notice that ObservableMap, ObservableSet, ObservableValue all doesn't use proxies. And make a direct implementation. Make sense for Set and Map. As you would just make a wrapper that keep the same methods as the native one. Proxies are for overriding operators. Like property access. And assignment operations.
You would notice too. That ObservableObject have the administration implementation that account for both proxies and annotation. And only the ObservableDynamicObject that implement the proxy, . And using the ObservableObjectAdministration. you can find the proxy traps there too.
Again, you can dig further if you want.
Otherwise, that's it. I hope that explained the whole well and went to some depth.

Angular 2 bind to computed getter gives debug erros

I am working with Angular 2 and lodash.
I have a model with Relations and I have a getter like that:
get relationsPerType() {
return _(this.Relations)
.groupBy(p => p.Type)
.toPairs()
.map(p => ({
type: <MessageRelationType>p[0],
relations: <Relation[]>p[1]
}));
}
Binding the value of relationsPerType to an *ngFor directive
Edit: This is my binding:
<div *ngFor="#relationGroup of Message.relationsPerType">
...
</div>
Gives me the following error:
Expression 'Message.relationsPerType in MessagesDetailsComponent#60:8'
has changed after it was checked. Previous
which seems to be perfectly right as indeed this is computed each and every time it is called.
In any case, having "computed" variables like that I can't imagine how Angular 2 change detection could detect that relationsPerType has actually changed.
Something like marking the getter as immutable??
I suppose a better way would be:
a) To store the computed getter values inside a property right from start
b) To make the parent object Immutable so as for Angular to not track changes on properties
Is there a better way to do this?
After some digging, I found a better way using decorators, than a) and b) has to offer, as:
a) I don't want to loose the "lazy" computations that getter functions provide and make everything a property
b) Immutable IS a viable solution but not applicable to my case
So, coming from C# and lots of Aspect Oriented programming (see PostSharp), I finally managed to create a cached property getter decorator function that is evaluated only once per object:
function cachedProperty(target: any, key: string, descriptor: PropertyDescriptor) {
let originalGetter = descriptor.get;
descriptor.get = function () {
let cachSetted = this[`__cachedsetted${key}`];
if (typeof cachSetted !== 'undefined') {
return this[`__cached${key}`];
}
this[`__cachedsetted${key}`] = true;
return this[`__cached${key}`] = originalGetter.call(this);
}
}
after that all that needs to change is decorate the getter with the #cachedProperty decorator, like so:
#cachedProperty
get relationsPerType() {
return _(this.Relations)
.groupBy(p => p.Type)
.toPairs()
.map(p => ({
type: <MessageRelationType>p[0],
relations: <Relation[]>p[1]
})).value();
}
Using this decorator the object will change only once so as for the Angular 2 dependency injection not to complaint. Also, I don't loose the "lazy" evaluations, and I don't add helper properties that changes my schema.
One must of course handle the case where he wants to invalidate the cache if this becomes stale. That would require to remove the
`__cachedsetted${key}`
property from this.
You should cache the value and bind to the cached value instead or create an observable that emits new events when data changes.
If you bind to {{relationsPerType}} a new collection is created every time Angular checks if a change happend and Angular sees this as change because it gets two different instances, even though they might contain the same data.
calcRelationsPerType() {
this relationsPerType = _(this.Relations)
.groupBy(p => p.Type)
.toPairs()
.map(p => ({
type: <MessageRelationType>p[0],
relations: <Relation[]>p[1]
}));
}
then binding like this should work fine:
<div *ngFor="#relationGroup of Message.relationsPerType">
...
</div>

React Flux implement dispatch chain

i'm trying to use React with Flux architecture and stumbled on one restriction which i can't handle.
Problem is as following:
There's a store which listens to an event. Event has object id. We need to fetch object if needed and make it selected.
If store doesn't have object with this id - it's queried. In callback we dispatch another event to store which is responsible for selection.
If store has object - i'd like to dispatch selection event, but i can't because dispatch is in progress.
Best solution i came up with so far is wrapping inner dispatch in setTimeout(f, 0), but it looks scary.
Actually the problem is quite general - how should i organize dispatch chain without dispatch nesting (without violating current Flux restrictions) if each new dispatch is based on previous dispatch handling result.
Does anybody have any good approaches to solve such problems?
var selectItem(item) {
AppDispatcher.dispatch({
actionType: AppConstants.ITEM_SELECT,
item: item
});
}
// Item must be requested and selected.
// If it's in store - select it.
// Otherwise fetch and then select it.
SomeStore.dispatchToken = AppDispatcher.register((action) => {
switch(action.actionType) {
case AppConstants.ITEM_REQUESTED:
var item = SomeStore.getItem(action.itemId);
if (item) {
// Won't work because can't dispatch in the middle of dispatch
selectItem(item);
} else {
// Will work
$.getJSON(`some/${action.itemId}`, (item) => selectItem(item));
}
}
};
Are you writing your own dispatcher? setTimeout(f, 0) is a fine trick. I do the same thing in my minimal flux here. Nothing scary there. Javascript's concurrency model is pretty simple.
More robust flux dispatcher implementations should handle that for you.
If ITEM_SELECT is an event that another Store is going to handle:
You are looking for dispatcher.waitFor(array<string> ids): void, which lets you use the SomeStore.dispatchToken that register() returns to enforce the order in which Stores handle an event.
The store, say we call it OtherStore, that would handle the ITEM_SELECT event, should instead handle ITEM_REQUEST event, but call dispatcher.waitFor( [ SomeStore.dispatchToken ] ) first, and then get whatever result is interesting from SomeStore via a public method, like SomeStore.getItem().
But from your example, it seems like SomeStore doesn't do anything to its internal state with ITEM_REQUEST, so you just need to move the following lines into OtherStore with a few minor changes:
// OtherStore.js
case AppConstants.ITEM_REQUESTED:
dispatcher.waitFor( [ SomeStore.dispatchToken ] );// and don't even do this if SomeStore isn't doing anything with ITEM_REQUEST
var item = SomeStore.getItem(action.itemId);
if (item) {
// Don't dispatch an event, let other stores handle this event, if necessary
OtherStore.doSomethingWith(item);
} else {
// Will work
$.getJSON(`some/${action.itemId}`, (item) => OtherStore.doSomethingWith(item));
}
And again, if another store needs to handle the result of OtherStore.doSomethingWith(item), they can also handle ITEM_REQUESTED, but call dispatcher.waitFor( [ OtherStore.dispatchToken ] ) before proceeding.
So, in looking at your code, are you setting a "selected" property on the item so it will be checked/selected in your UI/Component? If so, just make that part of the function you are already in.
if(item) {
item.selected = true;
//we're done now, no need to create another Action at this point,
//we have changed the state of our data, now alert the components
//via emitChange()
emitChange();
}
If you're wanting to track the currently selected item in the Store, just have an ID or and object as a private var up there, and set it similarly.
var Store = (function(){
var _currentItem = {};
var _currentItemID = 1;
function selectItem(item) {
_currentItem = item;
_currentItemID = item.id;
emitChange();
}
(function() {
Dispatcher.register(function(action){
case AppConstants.ITEM_REQUESTED:
var item = SomeStore.getItem(action.itemId);
if (item) {
selectItem(item);
} else {
$.getJSON(`some/${action.itemId}`, (item) =>
selectItem(item);
}
});
})();
return {
getCurrentlySelectedItem: function() {
return _currentItem;
},
getCurrentlySelectedItemID: function() {
return _currentItemID;
}
}
})();
Ultimately, you don't have to create Actions for everything. Whatever the item is that you're operating on, it should be some domain entity, and it is your Store's job to manage the state of that specific entity. Having other internal functions is often a necessity, so just make selectItem(item) an internal function of your Store so you don't have to create a new Action to access it or use it.
Now, if you have cross-store concerns, and another Store cares about some specific change to some data in your initial Store, this is where the waitFor(ids) function will come in. It effectively blocks execution until the first Store is updated, then the other can continue executing, assured that the other Store's data is in a valid state.
I hope this makes sense and solves your problem, if not, let me know, and hopefully I can zero in better.

Categories

Resources