Vue.js component lifecycle for children - vue.js

What order are child components created and mounted in? I know that the lifecycle for a single component is documented here, but I couldn't find anything that described when children were created and mounted.
For example, what is the creation and mounting order for the following component?
<template>
<div class='parent'>
<child-1/>
<child-2/>
<child-3/>
</div>
</template>

I found this article to be especially helpful in explaining the order of parent/child lifecycle hooks execution. This diagram in particular offers a nice summary of the process.
Also have a look at this post by LinusBorg on the vuejs forum.
beforeCreate() and created() of the parent run first.
Then the parent’s template is being rendered, which means the child components get created.
so now the children’s beforeCreate() and created() hooks execute respectively.
these child components mount to DOM elements, which calls their beforeMount() and mounted() hooks.
and only then, after the parent’s template has finished, can the parent be mounted to the DOM, so finally the parent’s beforeMount() and mounted() hooks are called.

In Vue 3, the lifecycle hook execution order can be found in a part of its tests.
The rule of thumb is: with the exception of created hooks (which are now replaced by setup()), all hooks prefixed with before executes top-down (parent run first) while the "after" hooks execute bottom-up (children run first).
Both beforeCreated and created hooks execute top-down, however (as a child can only be created after the parent renders).

As the first response give a good view of the creation/mounting process it fails to respond for the destruction process.
here is what happen :
app created
// we add the parent
parent Created
child Created
child Mounted
parent Mounted
// now we remove the parent :
parent ready to unmount
child ready to unmount
child unMounted
parent unMounted
PS : beware that beforeDestroy & destroyed in Vue 2 became beforeUnmounted & unMounted un Vue 3

Related

What is the difference between the beforeMount and the created lifecycle hook in vuejs

I am still unclear on where I should use the beforeMount and where the created lifecycle hook. It seems to me that in both, the reactive data has been loaded and it is before the DOM has been mounted.
In most cases it doesn't matter whether you use beforeMount or created but there are some where it matters:
Accessing original DOM element your root Vue component is mounting on
can be useful for integration with any server-side rendered framework (php, rails etc.)
explanation and example - When to use the lifecycle method beforeMount in vue.js?
in created hook this.$el is undefined, in beforeMount it's the original unmodified element, in mounted it's root element created by your component/template
Server-side rendering (Nuxt, Vuepress etc.)
docs
beforeCreate and created are only hooks called on the server
that means you should not use any code which needs window, document or any browser API in created as those will not be present on the server
on the other hand code placed in the beforeMount (or mounted) is executed only on the client (browser)
The beforeMount hook runs right before the initial render happens and after the template or render functions have been compiled(when vm.$el has not been created yet).
created is the step after initialization of your component(where you are able to access reactive data and events that are active with the created hook. Templates and Virtual DOM have not yet been mounted or rendered)

Vue JS Components structure

I am learning Vue and my doubt is about the structure of my Vue app.
I learnt that the components can include both logic and template. Then I separated my components and everyone is getting the config from the main app (config is an object with the coordinates config.ll, config.lng).
I do the ajax call to my search-and-discovery API service and I display the results inside each components (current location, venues-near-you etc).
My question is: is it correct to encapsulate the calls into each components? Or is it better to get the needed data inside the general app and then share the results with the components using pros?
I am asking that because the hard part is starting now when I want to communicate the click of a category to the venuesNearYou component, I tried to use the emit without success.
//MAIN
<sidebar :config="config"></sidebar>
<content :config="config"></content>
//IN SIDEBAR
<currentLocation :config="config"></currentLocation>
<categories :config="config"></categories>
//IN CONTENT
<venueDetails :config="config"></venueDetails>
<venuesNearYou :config="config"></venuesNearYou>
I think you could use event Bus like approach
we have three type of communication in vue app (without vuex)
Parent to child communication which is full field by props
child to parent communication handle by custom event from child which is listen by parent
communication between non parent child component in which we use event bus approach
Parent to child example
Child to parent example
In child this.$emit('sendDataToParent',{someData:"some data"}})
in parent
<child-component :somedata="dataToChild" #sendDataToParent="'gotsomedata from parent'">
Event Bus
in main vue instance
const eventBus = new Vue()
in some component from where to send data
import eventBus
eventBus.$emit('someEvent','some data')
in some component from where to receive data
created() {
// register listener
eventBus.$on('someEvent',()=>{
})
}
For more reference
https://v2.vuejs.org/v2/guide/components.html#Passing-Data-to-Child-Components-with-Props
https://v2.vuejs.org/v2/guide/components.html#Emitting-a-Value-With-an-Event
https://medium.com/easyread/vue-as-event-bus-life-is-happier-7a04fe5231e1
It's hard to help you around emitting an event since you didn't provide much of a code. But check Vuex. It serves as a centralized store for all the components in Vue application.

show loading spinner until all child components inside of a Page have been rendered - Nativescript

I'm trying to show an activity indicator, when I go from one page to another. The target page contains many components within it, and it takes time to load. that's why I need some way to listen when all the child components are loaded, and at that moment tell my variable isBussy to be false
<template>
<StackLayout>
<ActivityIndicator :busy="isBussy" v-if="isBussy" />
<StackLayout v-else>
<Component1 />
<Component2 />
<Component3 />
<Component4 />
</StackLayout>
<StackLayout>
</template>
<script>
import Component1 from '~/components/Component1'
import Component2 from '~/components/Component2'
import Component3 from '~/components/Component3'
import Component4 from '~/components/Component4'
export default {
data() {
return {
isBussy: true
}
},
mounted() {
this.$nextTick(function() {
// Code that will run only after the
// entire view has been re-rendered
this.isBussy = false
})
}
}
</script>
this code does not work, since once the navigation is indicated from the previous page with:
#tap="$goto('otherPage', { props: { foo: bar } })"
it remains stuck on the initial page, and all the components begin to load in the background of the destination page, but without displaying the parent page, changing to this, only when the whole process ends, and never show/hide the activity indicator as expected.
By the way this expected behavior works perfectly when i do request and process them with Promises, then I turn on or off a variable in the state and it works. but I can not replicate that behavior in the navigation between pages and listen to load all the components
EDIT
Finally I achieved the desired behavior with a little trick I found on the internet
mounted() {
setTimeout(() => {
this.isBussy = false
}, 500)
},
this causes that the rendering of all the children components is delayed only a little, so that the activity indicator is shown, but not too much to produce that none of the components contained in the else block is detected and begin to rendering
There are two main ideas to understand here I think. I'll describe both.
1. General technique to Fetch Data without blocking render
It sounds like you understand this concept at the parent component level but then are asking how to do something very similar for the child components that this page contains.
The way I handle this, is in my component, I have my data default to an isLoading state. Then, in beforeMount() or mounted(), I perform my asynchronous actions and make necessary changes to my page's data.
The problem becomes entirely recursive when we look at child components. You want to make sure your child components are rendering and that any long running data fetching that needs to occur within their implementation will simply cause them to re-render once that fetching is complete.
Here is a working example: https://codesandbox.io/embed/r4o56o3olp
This example uses Nuxt. Aside from the addition fetch() and asyncData() methods, the rest of the Vue lifecycle hooks are the same here.
I use new Promise and setTimeout to demonstrate an operation that would use promises and be asynchronous. (e.g. axios.get(..))
The About page loads, and the beforeMount() lifecycle hook performs the asynchronous fetching in a way that doesn't block the page from rendering.
I use the beforeMount() hook because, according to here ( https://alligator.io/vuejs/component-lifecycle/ ), it is the first lifecycle hook that we have access to once the page's data is reactive. (So modifying this.myDataProp would trigger a re-render if {{ myDataProp }} was used in the template).
I also included a child component where I purposely made its data take twice as long to load. Since I again, am letting the component render immediately, and then I handle the fetching/updating of data in an appropriate lifecycle hook, I can manage when the end-user perceives a page to be loaded.
In my working example, the LongLoadingComponent did the same exact technique as the About page.
Once you see how to use beforeMount() or mounted() to fetch data and then update state, I think the trick is to take a moment and really think about the default state of your component. When it first renders, what should the user see before any of it's data fetching/long-running operations are completed?
Once you determine what your default (not yet loaded) component should look like, try getting that to render on your screen, and secondarily add in the logic that fetches and updates state data.
2. Listening for when a Child Component is finished rendering from a parent component
This makes use of the above technique, but includes the usage of the updated() hook and emitting a custom event ( https://v2.vuejs.org/v2/guide/components-custom-events.html
)
If you really want to listen for when your child components are finished rendering, you can $emit a custom event in your updated() hook. Perhaps something like this (in one of your child components)
if (this.dataLoaded) { this.$emit('loadedAndRendered') }
So when the child's async operations are done, it can flip it's dataLoaded property to true. If dataLoaded is used in the child's <template> somewhere, then the component should re-render (for it's "finished" state). When the child re-renders, the updated() hook should trigger. (again, see: https://alligator.io/vuejs/component-lifecycle/ ) I included the if (this.dataLoaded) part just to handle case where updated() hook might be called during intermediate data updates. (We only want to emit loadedAndRendered event if child is finished loading data/updating.)
3. Other caveats about universal nuxt applications
It wasn't until after I wrote this answer that I realized you aren't using Nuxt. However I'm adding this in case other Nuxt users happen to come across this.
I'm adding this section just because it took some focused hands-on time for me to wrap my head around. A Nuxt Universal Application does both server-side and client-side rendering. Understanding when something renders on the client vs when it was rendered on the server was a little difficult for me at first. In the working example I linked above, when you visit the about page you can also see if that component was fetched from the server or if it was just rendered by the client.
I'd recommend playing with a Page's fetch() and asyncData() methods and see how it impacts when certain things render on your screen. ( https://nuxtjs.org/api/pages-fetch/ ) ( https://nuxtjs.org/api/ ). Seeing what these methods are useful for helps me also identify what they are not useful for.
If you're using a Vuex store, I'd recommend seeing what happens when you refresh a page or use instead of a to navigate between pages. (Seeing something like the SSR schema diagram can be helpful here: https://nuxtjs.org/guide#schema )
..I have yet to fully appreciate the details of the bundling and delivery behavior that Webpack provides for a Universal Nuxt app (See right side of diagram here: https://medium.freecodecamp.org/universal-application-code-structure-in-nuxt-js-4cd014cc0baa )

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.

How to check when a React Native component has finished RE-rendering?

I am currently re-rendering Child components within a Parent component based on a state change and I need to know when the child component has completely mounted and re-rendered on screen. Here's a quasi-example:
<Parent>
{ this.state.showChild1 ? <Child1/> : <Child2/> }
</Parent>
The general procedure for responding after state change would be using componentDidUpdate(prevProps, prevState) however, this lifecycle event only fires after state has updated without considering the effects of what the state change would update within the <Parent> component.
The problem I'm encountering then is that although state has completely updated, the new Child component is not yet available because it hasn't actually finished re-rendering yet. Is there a way to check when the Child components have re-rendered?
You could pass a callback into the component (sth like isMounted()) and call it in the child in the componentDidMount and componentDidUpdate lifecycle hook.
If you need this with arbitrary components you could iterate over them with React.Children.map(see docs) and add the lifecycle hooks on the fly (this is a bit error prone and you would need to have class components)