VueJs: How to determine in a watcher, whether the component is mounted? - vue.js

Seems like a simple requirement, and of course I could maintain my own flag using the lifecycle hooks. See also https://forum.vuejs.org/t/check-if-mounted-was-called/88177/6 for a similar question.
However, I prefer to use something already build-in. I am sure, VueJs maintains the lifecycle state somewhere.
Here's my watcher, simplified:
#Watch('openId')
private onOpenIdChanged() {
this.submitSomething(); //But ONLY if it's mounted!
}
How can I access the lifecycle state of the same component in a component's watcher, without using my own flag?

There is no public API for this, so the only correct answer is to maintain your own flag.
There is a private property on the component instance _isMounted which Vue uses internally (as of version 2.6.11).

Related

getDerivedStateFromProps() vs componentDidUpdate()

I am using componentWillReceiveProps in many places in my application. Now, I have to replace them with either getDerivedStateFromProps() or componentDidUpdate(). First I thought of using getDerivedStateFromProps as it s alternative of componentWillReceiveProps as suggested react-native docs. But some people are highly recommending not to use this method, Instead suggesting to use componentDidUpdate. But for my requirement all new props must be set with the state before render. getDerivedStateFromProps is the best place to do so.
Hence, which one to use between getDerivedStateFromProps and componentDidUpdate?
From the React docs
https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
getDerivedStateFromProps is invoked right before calling the render method, both on the initial mount and on subsequent updates. It should return an object to update the state, or null to update nothing.
Deriving state leads to verbose code and makes your components
difficult to think about.
Make sure you’re familiar with simpler alternatives:
If you need to perform a side effect (for example, data fetching or an animation) in response to a change in props, use componentDidUpdate lifecycle instead.
If you want to re-compute some data only when a prop changes, use a memoization helper instead.
If you want to “reset” some state when a prop changes, consider either making a component fully controlled or fully uncontrolled with a key instead.

How to share state between StencilJS components

I would like to share state between my StencilJS components. So I checked out the Redux implementation which they promote on their API site. It does something like
#Prop({ context: "store" }) store: Store;
But now I just red the BREAKING_CHANGES, which described that using context is deprecated. I actually liked using context but if this is deprecated, how can I share state between my components. I'm not really looking forward to pass everything from parent to child to etc.
The context API, even though deprecated, will still work, at least until the #stencil/redux package has been updated.
If you're looking for a simple alternative for global state, you should have a look at #stencil/store (https://github.com/manucorporat/stencil-store/tree/master/packages/stencil-store). It allows you to create a store with createStore(initalState) and returns a state reference which you can just import and reference in your component. When the store's state changes, the library will take care of triggering an update of your component.

Vue Component - How to handle non-reactive data?

I'm losing track of reactivity overhead best practices in a Vue 2 Component. I need to generate a one time string with genId() and assign it to the component' id attribute. It seems like overkill to have any watching going on after that.
Is :id="myID" the right way to insert this into the html id?
And then when setting up the source where do I put the non-reactive data? I had 3 thoughts:
Add property myID: genId() to data. But doesn't that add it to the watchlist automatically even though it won't change? Causing overhead?
I read on Vue Forum from a year old answer that myID: genId() should go in the created hook. Are using hooks for this kind of thing a best practice? I thought hooks were discouraged.
Or I could put it in the component methods and then call it directly with :id="genId()
Is there a Vue way to do this?
Use method 2 for non-reactive data (and you use that component many many times on the page that the small overhead of adding the change listeners has any impact.)
created() {
this.myId = genId()
}
The 3 methods behave differently:
Method 1: data
This will call the genId() when the data object is created and add change listeners.
Method 2: created hook
This will call the genId() when the component object is created and doesn't add change listeners.
Method 3: method
This will call the genId() every time the template re-renders. Which happens every time a change is detected on a variable the view is listening to or a $forceUpdate() is called.
Ps. Vue objects already have a unique id: this._uid
but this is a private property and might change in a future version of Vue.

Use of _self attribute from Vue vm is reliable?

I need pass the main component to a deeper child. Currently I am doing on child this.$parent.$parent, but is not reliable for me, because this same child could be in a third+ deepth level.
My idea is transfer the main component reference between childs, like:
<v-some-child :main-component="_self"></v-some-child>
So I can use the main component instance where I think need by passing the _self or this.mainComponent data to a more inner child.
My doubt is:
_self attribute is reliable to points to component Vue instance? Seems that _ prefix is to internal attributes, and $ for public (reliable). If it is true, what I can do use?
There are some better way to do what I wants?
Thanks!
Edit 1: as an immediate more reliable workaround, I am using data() { self: this }, then I am using :main-component="self".
I'm unclear where _self is getting set in your case. Typically _self = this; is an approach used by developers to pass the the current Vue instance via closure to a callback function. I wouldn't trust a _self unless I knew exactly where it was getting set.
Your edit1 should absolutely work. As long as data(){ self: this } is happening on the main Vue instance and in the components you use self when setting a property via a : like :main-component="self" then that should work fine given that the main Vue component data properties are merged into all components used by that vue instance.
It's kinda a cleaver approach frankly. As #raina77ow mentioned it may make sense to look at VueX or an EventBus but the approach you propose in Edit1 should be a reliable way to pass around the main Vue instance.
As an aside, I wonder if root or main might be a better name then self. Given that it's the "self" of the main or root level Vue instance not the the "self" of the child passing the value.

Invoke method in child component when the component is changed dynamically from the parent component

I have a simple component hierarchy, in which there is one parent component, which contains the following template <div><component :is="current"></component></div> and two child components, which are dynamically 'switched' out, via the value of current.
The logic for the 'switching' of components is being handled in the parent component. However, when I try to execute a method in the second child component (in response to an event emitted from the first child component, being listened to in the parent component, and altering the value of current in the parent component) through the mounted lifecycle hook, the expected result is not observed.
Essentially, I cannot find a decent way of invoking a child component's methods when that component is 'switched' in as the current component in the parent component.
I have realistically looked at using the $refs and $childrenproperties on the instance, but these do not seem to be of any assistance. I have also reasoned using the event system. I usually 'define' an event listener in the mounted lifecycle hook, however, I refer to the 'issue' of using the lifecycle hooks
What is the usual approach to this situation?
There are two options that immediately come to mind for child components invoking methods on being the "current" child component:
1) Using the mounted lifecycle hook. In order for this to work, you must be using v-if in order to conditionally display the child component, otherwise the child component will not trigger the mounted lifecycle hook. Otherwise, if you're using v-show or some other mechanism for conditionally displaying the child component, the mounted hook will only ever trigger once.
2) Using watched properties. In lieu of the above, you could do something like the following:
<child-component :target_prop="current"></child-component>
Vue.component('child-component', {
. . .,
props: ['target_prop'],
watch: {
target_prop: function() {
if(this.target_prop == your_expected_value) {
//execute the desired method for this component
}
}
}
});
This is, of course, just a proof-of-concept example and there are plenty of alternative ways to use the watched properties to your advantage.
I've also heard of using a "bus" to handle inter-component communication, but I don't believe it would be any better than the above two solutions (and is arguably worse).
Personally, I prefer the mounted lifecycle hook approach, though there's the caveat that any "settings" or data in your child components will be lost on switching between them (although you could also emit a settings object on destruction and store/restore those settings as needed, but that could get messy). You'll have to make the final judgment on which approach better suits your needs and which consequences you're more comfortable dealing with.