Triggering a CSS animation upon a Vue component being mounted - vuejs2

I want to trigger an animation to run as soon as a component is mounted.
I've put the change inside a $nextTick function inside the mounted callback but it appears that it applies immediately before the component is first rendered, so the item appears in its final state without playing the animation to reach that point.
A fiddle of the problem is here: https://jsfiddle.net/j1oupq5e/1/
The relevant mounted function is as follows (width starts at 1px by default):
mounted() {
this.$nextTick(function(){this.width="100%"})
}
How can I make that animation start playing upon the component being mounted?

you can call setTimeout function :
mounted() {
let _this=this;
setTimeout(function(){
_this.$nextTick(function(){_this.width="100%"})
},0);
}

Related

Vue3 child component does not recreating, why?

I have made some sandbox code of my problem here:
https://codesandbox.io/s/clever-zeh-kdff1z
<template>
<div v-if="started">
<HelloWorld :msg="msg" #exit="exit" #remake="remake" />
</div>
<button v-if="!started" #click="started = !started">start</button>
</template>
<script>
import HelloWorldVue from "./components/HelloWorld.vue";
export default {
name: "App",
components: {
HelloWorld: HelloWorldVue,
},
data() {
return {
started: false,
msg: "Hello Vue 3 in CodeSandbox!",
};
},
methods: {
exit() {
this.started = false;
},
remake() {
this.msg = this.msg + 1;
//this code should recreate our child but...
this.exit();
this.started = true;
// setTimeout(() => {
// this.started = true;
// });
},
},
};
</script>
So! We have 2 components parent and child. The idea is simple - we have a flag variable in our parent. We have a v-if statement for this - hide / show an element depend on the flag value "false" or "true". After we toggle the flag - the child component should be recreated. This is the idea. Simple.
In our parent we have a button which will set the flag variable to "true" and our child will be created and will appear on our page.
Ok. Now we have 2 buttons inside our child.
One button is "exit" which is emit an event so the flag variable of parent will set to "false" and the elemint will disappear from our page(It will be destroyed btw). Works as charm. Ok.
The second button "remake". It emit event so the flag variable will be just toggled (off then on). Simple. We set to "false", we set to "true". So the current child should dissapear, and then imediatly will be created new one.
But here we are facing the problem! Ok, current child is still here, there is no any recreation, it just updates current one... So in child I have checked our lifecycle hooks - created and unmounted via console.log function. And the second button dont trigger them. Start->Exit->Start != Start->Remake.
So can anyone please explain me why this is happening? I cant figure it out.
Interesting thing, if you can see there is some asynchronous code commented in my demo. If we set our flag to "true" inside the async function the child will be recreated and we will see the created hook message but it seems like crutch. We also can add a :key to our component and update it to force rerender, but it also seems like a crutch.
Any explanations on this topic how things work would be nice.
Vue re-uses elements and components whenever it can. It will also only rerender once per tick. The length of a 'tick' is not something you should worry yourself about too much, other than that it exists. In your case the this.exit() and this.started = true statements are executed within the same tick. The data stored in this.started is both true in the last tick and the current tick as it does not end the tick in between the statements, and so nothing happens to your component.
In general you should think in states in Vue rather than in lifecycles. Or in other words: What are the different situations this component must be able to handle and how do you switch between those states. Rather than determining what to do in which point in time. Using :key="keyName" is indeed generally a crutch, as is using import { nextTick } from 'vue'; and using that to get some cadence of states to happen, as is using a setTimeout to get some code to execute after the current tick. The nasty part of setTimeout is also that it can execute code on a component that is already destroyed. It can sometimes help with animations though.
In my experience when people try to use lifecycle hooks they would rather have something happen when one of the props change. For example when a prop id on the child component changes you want to load data from the api to populate some fields. To get this to work use an immediate watcher instead:
watch: {
id: {
handler(newId, oldId) {
this.populateFromApi(newId);
},
immediate: true
}
}
Now it will call the watcher on component creation, and call it afterwards when you pass a different id. It will also help you gracefully handle cases where the component is created with a undefined or null value in one of the props you expect. Instead of throwing an error you just render nothing until the prop is valid.

How to wait for variable in window object before render a Vue component?

I have a component that need to access variable inside window object. But it renders before it loaded. So is there any solution delay that component render until variable will exists?
you can try to wrap it into a
this.$nextTick(() => {
// ur code here
})
nextTick is a function which waits till the dom is complete loaded and executes the content inside.

How to determine what causes components to rerender

I am having an issue where when I change a component in my app, many unrelated components seem to be rerendering too. When I use the Vue performance timings config, I see something like (all in the span of about 200ms)
I am trying to figure out what causes these components to rerender. I saw a tip about how to tell the cause of a rerender, but when I put this snippet* in all the rerendering components, I don’t get anything logged to the console.
So, how can I find what is causing all these components to rerender?
*The code I actually put looks like
public mounted() {
let oldData = JSON.parse(JSON.stringify(this.$data));
this.$watch(() => this.$data, (newData) => {
console.log(diff(oldData, newData));
oldData = JSON.parse(JSON.stringify(newData));
}, {
deep: true,
});
}
Using the F12 dev tools in Chrome, you can track down what is triggering your component to re-render. Add an updated hook to your component as below:
updated() {
if (!this.updateCnt)
this.updateCnt = 1;
if (this.updateCnt > 1) { // set to desired
debugger;
}
console.log(`Updated ${this.updateCnt++} times`);
}
}
Refresh your page in Chrome with F12 tools open and wait for breakpoint to be hit. In the Sources tab, you will see the call stack on the right, with your updated() function as the current stack frame. Look back up the call stack and eventually you should see the code that caused the update to trigger. In my case, it was reactiveSetter() in the vue runtime, which was triggered by me setting a property in a parent component.
The code you have above will only trigger if a component's own state changes, not a parent.

Nuxt/Vuejs Event to fire when page done rendering all the components

I need to fire an event when page is done with rendering all the components. I have tried page mounted event but this fires only for the first time, I need to fire an event when the route changes on client side and new component is done rendering.
How about using updated . I used that for data changing state . Hope you get some help from this tips
updated: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
})
}

How to get div in nested child component during mounted - Vue.js

I have problem whit scrolling to the element while opening the page. It's like scrolling to an anchor. I'm sending div id via props to the nested child component. On mounted I call a method scrollToSection where I have logic with scrolling.
props: {
section: String
},
mounted() {
this.scrollToSection();
},
methods: {
scrollToSection () {
if (this.section != null) {
const options = {
force: true,
easing: 'ease-in',
};
VueScrollTo.scrollTo(`#${this.section}`, 100, options);
}
}
}
In that point child component dosen't render the DOM and document.getElementById(this.section) return null. But in parent component I have an access to that div.
Do you have any idea how to resolve that issue? Method nextTick dosen't work.
Had the same problem, where I needed to access an image in a nested component, I had to wait till the image is loaded within the nested component, by adding a #load event listener that emit a loaded event to the parent, so I knew it was ready and perform my actions.
If nextTick isn't working, you can do the same, just emit a ready event on the mounted hook of the child component and when it's ready, perform the scroll.
//Child component
mounted(){
this.$emit('ready');
}
_
//Parent component
...
<child-component #ready="scrollToSection()" />
...
Or in alternative, if you have access to the div you want to scroll to, you can use pure javascript
MyDiv.scrollIntoView({ block: "start", behavior: 'smooth' });