I'm using the Objective-C API, though I would imagine that this question is valid regardless of language.
I'm trying to write my code so that my app observes when child objects are removed from a particular node. When a child object is removed, I make local changes so that the local version of that child object is deleted.
I also have observers set for each child object's children on Firebase. This is so that I can propagate changes to those values locally as soon as they are made.
My observers are (finally!) working just fine – except that when I delete an object from Firebase, it seems like the observers for the object's children are triggered before the observer for the object's parent. E.g.,
If I have several blog posts listed under $userId/blogs/ according to their $blogId, and if each blog post has properties such as name and text, it seems like the FEventTypeValue observers at $userId/blogs/$blogId/name and $userId/blogs/$blogId/text are triggered before the FEventTypeChildRemoved observer at $userId/blogs when I set a particular $blogId to nil.
Any idea how I can set it so that the FEventTypeChildRemoved observer triggers before the FEventTypeValue observers? The alternative would be to always check whether the parent object exists when observing a change to a property on Firebase, but this to me seems like overkill.
Related
I have a relatively complex API request object I need to make, with a large number of UI components responsible for updating different properties of the object.
I'm passing the basic request model as a prop from a parent component to its children, which pass it on to theirs (down several "generations").
At the parent level, I have a computed property that returns a field of this data model, and a watch on that computed property.
When a child component updates the property on the model, it successfully updates everywhere that has a reference to it, but the computed property on the parent fails to recalculate, and resultantly the watch never activates.
I'm guessing I've missed the point somewhere along here, but I can't think about how else to update without resorting to long event chains through the UI.. How should I be approaching this instead?
To anyone with a similar question - from my research it seems that modifying reference values on props is not the intended approach for VueJS. Which is a shame, because initially it seemed like quite a neat pattern.
I've implemented vuex now, which is working well, and avoids long lines of events going back to the original owner of the prop data.
IF you wanted to press it, then modifying references on the object itself will force updates down the chain. So (e.g.) if you wanted to update an array property of the prop data, then instead of "pushing" to it, you would replace the whole array object (causing other components with computed properties on that array property to recalculate). But again, not recommended.
As you know, for each data property, there's a new Dep class created. Each Dep class has subscribers of watchers.
I looked through vue.js source code and for each component, there's only ONE watcher class being created which also holds the render function(template of the component).
1) Could you describe the situation when and why data property of one of the components might have the Dep class which has more than one watcher class?
2) So can I sum up something like this: if we have a component which has 5 data properties. each of these 5 data properties has different Dep class instance. and each of those Dep class has the same Watcher and that watcher holds the component's render function. If state changes, one of those 5 Dep class's notify gets run and that notify runs its watcher's render function?
You may find this introduction useful:
https://medium.com/dailyjs/tracing-or-debugging-vue-js-reactivity-the-computed-tree-9da0ba1df5f9
As you've mentioned, each data property will have its own instance of Dep. Each Dep has a subs property that holds an array of subscribers. The subscribers in that array will all be instances of the Watcher class. If a data property changes then the corresponding Dep will notify each Watcher in its subs.
Each Watcher also holds references back to its dependencies, in a property called deps. This is just an array of the Dep objects to which the Watcher is subscribed.
You'll be able to see this in your browser developer tools. If you log a Vue instance you'll find a property called _watchers that holds all the watchers related to that component. Expanding their deps will lead you to the Dep objects, though it can be tricky to tell exactly which data property each Dep represents.
The rendering process has a Watcher that it uses to track its data dependencies. You'll only get one of those per component instance.
A Watcher is also created if you use watch or $watch. Again you'll be able to see these in _watchers.
Computed properties have one Watcher each. Those will be present in the _watchers array but it's easier to see them in _computedWatchers.
A key thing to note is that dependencies are flattened. If you use a computed property you'll actually just get a dependency on all the data properties that contributed to it. You can't form a direct dependency on the computed property itself.
So to go back to your original question:
Rendering, computed properties and watch will all contribute to the subs of a Dep. Computed properties will often contribute more subscribers than you might expect due to the flattening of the dependencies.
Almost. The render function isn't called directly. When the Watcher for rendering is notified of a data change it will actually just add the component to a queue. That rendering queue won't be processed until the start of the next tick.
Is is possible to emit a synthetic event from a watched property in a way, that will not be checking the listeners (outside of Vue instance) on Vue instance initialization?
I have a situation in which I would like to watch for that synthetic event on a window object and perform a certain action on an object which does not exist at the time the Vue instance is created.
No matter how I try it to go about it I am getting an error:
Cannot read property 'set' of undefined
In my particular case, I want to 'move' the slider handle (I am using noUiSlider library) to a new position whenever the watched property changes - that is, the error message is specific, but my question refers to the generic case - is it possible? And if yes, how to do it?
For the listener to be able to operate on the slider, create the listener when you create the slider. There's no point to creating it before the slider exists.
I'm discovering VueJS and I don't understand exactly the differences between updated and watchers.
Updated hook
It is a lifecycle hook. According to the official documentation, it is triggered whenever data changes. So whenever a prop or a data is updated (the value, not only the pointer), updated is called.
Watchers
In the documentation, watchers are compared to computed properties. But in which cases would it be best to use updated instead of watchers ?
It seems that in both cases, DOM is not updated when the callback is called (nextTick() is required if we want to manipulate the changes in the DOM). The only difference I see is that watchers are only triggered when one precise property (or data) is updated where updated is always called.
I can't figure out what are the pros of updating whenever a data changes (updating) if we can be more accurate (watchers).
Here are my thoughts.
Thanks :)
The lifecycle hooks around update respond to changes in the DOM. Watchers respond to changes in the data. DOM changes are generally in response to data changes, but they might not be data owned by the component in question. One example where updated could be used is noticing that slot content has updated.
I think a better analogous lifecycle hook to the watchers may be the beforeUpdate hook. The updated hook is called after the virtual DOM has re-rendered, whereas beforeUpdate is called before the virtual DOM has re-rendered. You can see a visual representation of this on the diagram you linked to.
in which cases would it be best to use updated instead of watchers ? (...) I can't figure out what are the pros of updating whenever a data changes (updated) if we can be more accurate (watch).
The documentation says that you should prefer a watcher or computed property instead of updated if it is possible to achieve your goal that way. My understanding is that the updated hook was included to allow users to watch for any changes to the virtual DOM (see below).
Here's the explanation from the Vue 2.0 release notes on watch vs. updated:
User watchers created via vm.$watch are now fired before the associated component re-renders. This gives the user a chance to further update other state before the component re-render, thus avoiding unnecessary updates. For example, you can watch a component prop and update the component's own data when the prop changes.
To do something with the DOM after component updates, just use the updated lifecycle hook.
I have an external library with TypeScript class instances in observed variable of my app's store:
class Store:
#observable active_obj:ExternalClass;
This instance has a method which, when called, updates its internal state leaving the object as is:
store.active_obj.change()
Now, since Mobx is not observing this object itself nor its (I assume) properties, only changes happening directly on the field active_obj (like new value assigned to it). Since instances of MyClass are provided by external library and ultimately get rendered inside this library's components I can't add observables and observers to its class structure nor React components. Mind you, this is only what I think is the reason that changing the object's properties doesn't trigger re-render...
I had to cheat a bit by using other, observed variable I change directly with nonsense data at the same time I'm calling to unobserved instance for change. Adding references to this variable on components higher up the tree, I can trigger re-render that produces updates on the (unobserving) components of the external library.
My question is, how best to make Mobx aware of change so it can notify observers of store.active_obj instance?
I think this part of Mobx documentation warns about this, but there's no workarounds or solutions for it:
** If likes where objects instead of strings, and if they were rendered by their own Like component, the Likes component would not rerender for changes happening inside a specific like.
from here, at end of the page
Edit
As per #mweststrate's question, I provide some context:
My app controls its data, but it has to create external class' instances from that
Instance's data is encapsulated and mutated in place, but it's done by asking from my app's side through user triggered events (meaning, I know when data is updated)
Basically class uses app's data to provide different views into data based on user selection and renders it with its React components
I also use this changed data elsewhere in the app in components I control
Changed data is part of external class' internals and I can't depend on it
Since Mobx tracks mutations it can see, using Observable doesn't directly work
Some possible solutions I thought:
manually notify observers that observable active_object has changed when I have called the instance it references to change
have a container object that Mobx can track and when I change its sentinel property, that update is noticed and actual instance with it