use onMounted Hook - vue.js

I'm using nuxt3 with vue3 for my website.
But I have problem when using onMounted hook.
here is my vue page.
<script setup lang="ts">
import { onMounted } from '#vue/runtime-core';
onMounted(() => {
console.log('myheader mounted');
})
</script>
<template>
<h1>test</h1>
</template>
I get this errors:
[Vue warn]: onMounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement.
It makes me confused...... T.T

Nuxt requires importing the hooks from vue, not #vue/runtime-core:
<script setup lang="ts">
// import { onMounted } from '#vue/runtime-core'; ❌
import { onMounted } from 'vue'; ✅
onMounted(() => {
console.log('myheader mounted');
})
</script>
demo 1
Or use auto imports instead. That is, omit the import, and let Nuxt automatically import onMounted from the correct package:
<script setup lang="ts">
// onMounted auto imported ✅
onMounted(() => {
console.log('myheader mounted');
})
</script>
demo 2

Related

Vue: How do I call a function inside a Component?

I am trying to execute a function from the Food.vue component from Page.vue.
How can I execute a function from an imported component?
I am using Vue 3 Composition API.
This is what I am trying to do:
Food.vue Component
<script setup>
var food = "blueberry"
function changeFood () {
food = "cherry";
}
</script>
<template>
<div>{{food}}</div>
</template>
Page.vue
<script setup>
import { onMounted } from "vue";
import food from "#/components/Food.vue";
onMounted(async() => {
// I want to execute changeFood() from the imported component. How can I do this?
});
</script>
<template>
<food></food>
</template>
I know this can be done with page props, but that's not what Im trying to do. I am trying to execute a function.
You have to expose the method to the parent using defineExpose;
Food.vue
<script setup>
import { ref } from "vue";
const food = ref("blueberry");
const changeFood = () => {
food.value = "cherry";
};
defineExpose({ changeFood });
</script>
<template>
<div>{{food}}</div>
</template>
Page.vue
<script setup>
import { ref, onMounted } from "vue";
import food from "#/components/Food.vue";
const myFood = ref(null);
onMounted(async() => {
if (myFood.value) {
myFood.value.changeFood();
}
});
</script>
<template>
<food ref="myFood" />
</template>
Demo

vue.js 3 .value.click is not a function

<template>
<RecyclablesPopup ref="LVP" class="inline-block m-5px"></RecyclablesPopup>
</template>
<script setup>
import RecyclablesPopup from "../components/popups/RecyclablesPopup";
import { ref } from 'vue';
const LVP = ref(null);
// ... after mounted I have an event with a legacy component and onclick handler:
eventClick: function(calEvent)
{
console.log(LVP.value);
LVP.value.click();
}
</script>
At the end I get Uncaught TypeError: LVP.value.click is not a function after I clicked.
console.log returns me the proxy object as expected Proxy { <target>: Proxy, <handler>: {…} }
Why can't I call click()?
the click function should be exposed by the child component in order be accessed by the parent component :
RecyclablesPopup component
<script setup>
function click(){
//.......
}
defineExpose({
click
})
</script>
for more details please check https://vuejs.org/guide/essentials/template-refs.html#ref-on-component
If you are using script setup you can't access functions, variables, etc., defined inside the referenced component. To change that you have to use the defineExpose compiler macro inside RecyclablesPopup component - check more in documentation
//inside RecyclablesPopup
<script setup>
import { ref } from 'vue'
const click = () => {
//do something
}
defineExpose({
click,
})
</script>
You need to execute the function on the onMounted lifecycle to guarantee that the component is mounted to the DOM, as the value before the component is mounted will be undefined.
onMounted(() => {
eventClick()
})
For more resources
https://vuejs.org/api/composition-api-lifecycle.html#onmounted

Vuejs script setup cannot contain ES module exports

Following the setup guide for Vuejs and Pinia
<script setup>
import {useStore} from "../stores/store.js";
export default {
setup() {
const store = useStore();
return {
store,
}
},
}
</script>
I get the following error from Vite:
[vite] Internal server error: [#vue/compiler-sfc] <script setup> cannot contain ES module exports. If you are using a previous version of <script setup>, please consult the updated RFC at https://github.com/vuejs/rfcs/pull/227.
How do I move to a version of <script setup> that will allow me to do the above?
Thanks!
A bit of confusion on my end it seems. The docs talk about adding <script setup> and then also demonstrate using setup(){}, but they don't explicitly state that its one or the other.
Method 1:
<script setup>
import {useStore} from "../stores/store.js";
const store = useStore();
// do stuff
</script>
Method 2:
<script>
import { defineComponent } from 'vue'
import {useStore} from "../stores/store.js";
export default defineComponent({
setup() {
const store = useStore();
// do stuff
return {
store,
}
}
})
</script>
I think you mismatched two methods of local components registration.
Check:
https://vuejs.org/guide/components/registration.html#local-registration
https://vuejs.org/guide/reusability/composables.html#what-is-a-composable
When using SFC with , imported components are automatically registered locally:
<script setup>
import { useStore } from '../store/store.js'
const { store } = useStore()
</script>
Add Following code to your main.js file
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
.use(createPinia())
app.mount('#app')

Property 'info' does not exist on type 'Vue' in async method of Nuxt js

I am trying to store a response from an api in the async method of my Nuxt js application in a variable info. I am getting this error: Property 'info' does not exist on type 'Vue'. If I put the same Axios call in mounted, there is no error. This is what I have:
<template>
<div>
{{ info }}
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import axios from 'axios';
#Component({
async asyncData(): Promise<any> {
await axios
.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(response => (this.info = response)); <--- The error is here
},
})
export default class MainClass extends Vue {
info: any = null;
....
}
</script>
Would appreciate some help, thanks!
this does not refer to your component. You don't have access to the component instance through this inside asyncData because it is called before initiating the component.

Getting [Vue warn]: Unknown custom element: <b-modal> even though bootstrap-vue is registered

A BootstrapVue b-modal component in a custom Vue component loads correctly in the browser. However, when testing using mocha+mochapack, it generates a Vue warning that the b-modal element is not registered. The test is using a localVue object that has BootstrapVue registered. All other bootstrap custom elements seem to be loading correctly, and do not generate any warnings.
I tried various things, including importing BModal from 'bootstrap-vue' and registering it as a component directly, but still got the same error.
import {mount, createLocalVue} from "#vue/test-utils"
import MyCustomModal from '../js/MyCustomModal';
const localVue = createLocalVue();
import BootstrapVue from 'bootstrap-vue'
localVue.use(BootstrapVue);
describe('MyCustomModal', () => {
let wrapper = mount(MyCustomModal,{
localVue
});
it('the content is "this is the content"', () => {
expect(wrapper.find(".modal-content").text()).toEqual('this is the content');
});
});
The custom Vue component:
<template>
<b-modal>
<div class="modal-content">this is the content</div>
<b-form>
my form
</b-form>
</b-modal>
</template>
<script>
export default {
data(){
return {};
}
}
</script>
The tests run correctly and pass, but it outputs the Vue warning for the b-modal element. It doesn't output the warning for b-form.
If only shallowMount not work.
You can try stub your bootstrap's components individually.
Like this:
import {shallowMount} from "#vue/test-utils";
import { BModal, BForm } from 'bootstrap-vue';
import MyCustomModal from '../js/MyCustomModal';
describe('MyCustomModal', () => {
let wrapper = shallowMount(MyCustomModal,{
stubs: {
"b-modal": BModal,
"b-form": BForm
}
});
it('the content is "this is the content"', () => {
expect(wrapper.find(".modal-content").text()).toEqual('this is the content');
});
});
You need to set the attachToDocument: true flag when you mount b-modal (or your test component/app). It needs reference to the document/body in order for it to open (needs to add classes, etc to <body> as well as a few listeners.
import Vue from 'vue';
import {mount} from "#vue/test-utils"
import MyCustomModal from '../js/MyCustomModal';
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue);
describe('MyCustomModal', () => {
let wrapper = mount(MyCustomModal);
it('the content is "this is the content"', () => {
expect(wrapper.find(".modal-content").text()).toEqual('this is the content');
});
});
Try that.