Which way better to create vue component (export default vs defineComponent vs new Vue) - vue.js

After learning Vue.js lately, i'm pretty match confused about how to write vue component syntax
i keep seeing youtube tutorials, as well as articles, and everyone uses a different approach.
in terms of vue 3
should we use
export default to create a component
or export default defineComponent
or new Vue({
so how to decide the right way on how to create App component and the rest of its child components and pages etc ..
Hopefully my question is clear enough.
Thanks

If you need to create multiple components I would highly recommend using Single File Components (SFC)
Here you define a new component as (inside the <script> tag):
import { defineComponent } from 'vue'
export default defineComponent({
// ...
})
(or export default {} if not using TypeScript)
For the main app component you would do this:
import { createApp } from "vue";
const app = createApp(App)
app.mount('#app')
OR just like this, if you don't need to extent Vue with vue-router, Vuex etc.
import { createApp } from "vue";
createApp(App).mount('#app')

Related

Vue 3 - how to include components and mixins with the root component?

I try to convert the syntax from Vue 2 to Vue 3, but I'm not sure how to include the mixins and components, if you see this code from Vue 2:
import App from "./App.vue";
const app = new Vue({
mixins: [globalMixin],
router,
el: '#app',
store,
components: {
Thing,
Hello
},
render: h => h(App)
});
Here is the Vue 3 syntax, if I've understood it right:
const app = createApp(App)
app
.use(store)
.use(router)
app.mount('#app')
The vue 2 example has a mixin and two components, but how do I add that to the Vue 3 syntax?
You can add a component by doing : app.component('Thing', Thing) but that's only one component...should I add them one by one in that way? What about the mixins?
In Vue 3, it's possible to do local component registration and mixins in the root component (useful when trying to avoid polluting the global namespace). Use the extends option to extend the component definition of App.vue, and then add your own mixins and components options:
import { createApp } from 'vue'
import App from './App.vue'
import Hello from './components/Hello.vue'
import Thing from './components/Thing.vue'
import globalMixin from './globalMixin'
createApp({
extends: App,
mixins: [globalMixin],
components: {
Hello,
Thing,
}
}).mount('#app')
Registering the component one at a time seems like the way to go, especially if there are only a few components.
demo
In Vue 3, you can use the application API mixin method.
import { createApp } from 'vue'
import App from './App.vue'
import globalMixin from './globalMixin'
const app = createApp(App)
app.mixin(globalMixin)
app.mount('#app')
For components, you can add them one by one. I prefer it this way because it is cleaner.

Vue: When to register component in main.js vs in the .vue file

Say I have a basic vue project
main.js:
import { createApp } from 'vue';
import App from './App.vue';
import SomeComponent from './components/SomeComponent.vue';
const app = createApp(App);
app.component('some-component', SomeComponent);
app.mount('#app');
components/App.vue:
<template>
<some-component></some-component>
</template>
<script>
import SomeComponent from "./SomeComponent.vue";
export default {
components: { SomeComponent },
};
</script>
components/SomeComponent.vue:
<template>
<div></div>
</template>
<script>
export default {};
</script>
Note that in main.js, I call app.component('some-component', SomeComponent); and in SomeComponent.vue I also specify the same with components: { SomeComponent },. Only one of the two ways is needed (though specifying both doesn't seem to cause errors).
My question is this: When would you specify components in main.js instead of in the component that will actually use it?
It seems that I could create an entire storefront and list all of the components in main.js without ever using components: {} inside a single one of my components and it would work. But it seems more logical to me to list the used sub-components inside each component that will use them for the encapsulation and reusability it brings. But that's because I have an object oriented mindset.

Can't access this.$store (vuex) in any child component after basic installation

So I am totally new to vuex. I carefully install the vuex to my vue app but I can't acess the this.$store in any of my child component.
I have also read more than 10 questions ask the same thing and I did a lot of changes, tried lots of times. Since I thought I did everything right and it still doesn't work. I finally decide to come here and ask. I will put my own codes below:
file structure (only related files):
|---main.js
|---store.js
|---App.vue
|---components
main.js:
import '#babel/polyfill'
import Vue from 'vue'
import App from './App.vue'
import './plugins/vuetify'
import './plugins/vue-resource'
import { store } from './store';
require('../node_modules/ol/ol.css');
Vue.config.productionTip = false
fetch('static/App_Config.json')
.then(function (response) {
return response.json().then(function (AppConfig) {
Vue.prototype.$AppConfig = AppConfig;
new Vue({
store,
render: h => h(App)
}).$mount('#app')
});
})
store.js:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex, {
});
export const store = new Vuex.Store({
state: {
testText: "test string"
}
});
in components: (simplified, only related codes)
<script>
created () {
console.log("this.$store_test: ", this.$store);
}
</script>
I have already tried these possibilties:
in main.js:
use import store from './store'; rather than import { store } from './store';
in main.js:
use store: store, rather than store,
in store.js:
use Vue.use(Vuex); rather than Vue.use(Vuex, {});
in store.js: (combined with 1. I have tried all 4 combinitions)
use export default store = new Vuex.Store rather than export const store = new Vuex.Store
put the console not in created hook, but in methods, and made a button to trigger it.
put the console in other child components, which nested in different deeps
After I serched a lot similar qustions and tried a lot (also with 20+ time server restart). I still can get this.$store. I kind of need some help.
I DO NOT think this question is duplicate, because I have already read other questions and tried all the possiblities. If they all failed, it must be something new here with mine codes.
This is a valid Vuex store.js file:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
testText: "test string";
}
});
export default store;
Remember to create a getter, mutation and action for your variables in Vuex, you should not handle the state directly.
It doesn't matter in main.js if you use store or store: store, they are identical.
import store from './store' is the same as import { store } from './store'.
Vue.use(Vuex) and Vue.use(Vuex, {}) are the same as long as you don't supply any options.
You don't need to get the store in a component somewhere, you're loading Vuex before the app is mounted, so you can actually start using it in e.g. the main.js created hook.
Your components <script> tag is incorrect. You should use export default, like this:
<script>
export default {
created () {
// Check if console.log like this works better as well
console.log("Store test:");
console.log(this.$store);
}
}
</script>

showing Vue is not defined error while importing vue-router

I have created a new project using vue-cli 'vue init webpack-simple my-app' command. In that fresh installation copy, I'm trying to import vue-router in the App.vue component that was created by default. But it is giving me an error: 'Uncaught ReferenceError: Vue is not defined'. If I import the vue again in App.vue, then the app is working fine. But I already imported the vue in main.js, so why do I need to import it again in App.js? Is there any way I can use the imported vue from main.js? Here is my code:
main.js:
import Vue from 'vue'
import App from './App.vue'
new Vue({
el: '#app',
render: h => h(App)
})
App.vue:
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
import Vue from 'vue'; //**why I need to import it again? I already imported it in main.js
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import QuestionOne from './components/QuestionOneTemplate';
const routes = [
{ path: '/', name: 'QuestionOne', component: QuestionOne },
];
const router = new VueRouter({
routes
});
window.router = router;
export default {
router,
name: 'app',
data () {
return {
}
}
}
</script>
<style lang="scss">
</style>
Is there any way i can use the imported vue from main.js?
No, you need to import it in every file that uses Vue. The imports/requires are how things get hooked up. Rest assured, each import will be the same singleton instance.
You can get to the router from a Vue component's javascript using this.$router and this.$route without an import, or inside a template, using simply $router and $route
Not recommended, but you can assign Vue to a global in main.js, and use the global without importing.
main.js
import Vue from 'vue';
global.MyVue = Vue
App.vue
import VueRouter from 'vue-router';
MyVue.use(VueRouter);
Why
This is how ES6 links things up. Consider it wiring. If there were more than 1 Vue lib available, how would the linker know which to use? What if another library defined a variable or function called Vue? Perhaps a lib uses its own internal Vue for an event bus or other feature.
Other Thoughts
The explicit import also makes IDE autocompletion and syntax highlighting work better. Some IDEs can add the imports automatically, and that makes life easier.
did you try this ?
import Vue from 'vue'
import VueRouter from 'vue-router'
then use
Vue.use(VueRouter)
because the error message means you need to import vue first to use vue-router
You did the right thing and you don't have to worry about importing Vue in multiple files. When you are shipping your application and build it for production, you will have only one "Vue import". If you take a look at dist folder and your bundled .js files you will notice that Vue is imported only once.

Vuejs and Webpack: Why is store undefined in child components

I am using Vuejs with Webpack.
Here's store.js:
import Vuex from "vuex";
export default new Vuex.Store({
state: {
count : 0
},
mutations: {
increment (state) {
state.count++
}
}
});
Here is my app.js:
"use strict";
import Vue from 'vue';
window.Vue = Vue;
import MyComponent from './MyComponent.vue';
import store from './store.js';
window.App = new Vue({
el : '#my-app',
store,
components : {
'my-component' : MyComponent
}
});
Here is the script from MyComponent.vue:
export default {
computed : {
count() {
return this.$store.state.count;
}
},
mounted() {
console.log(this.$store)
}
}
Any reference to this.$store in my component is undefined. Why?
You need to install the Vuex plugin somewhere to allow Vue components to access the store. As Pavan noted, to do this you must include the following lines somewhere (in your app's index.js, in your store.js etc) before you create your Vue instance:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
This tells Vue what to do with the store instance when you create the instance, which will make it available under this.$store in your components. This also ensures that Vuex also knows how to interact with Vue. Without it, you will not be able to use Vue and Vuex together properly.
Regarding your later answer, you can export the store instance just fine, and import it into your index.js, router config etc. For example:
store.js:
import Vuex from "Vuex";
export default new Vuex.Store({ /* store config */ });
MyComponent.vue's <script> block:
export default {
mounted() {
console.log(this.$store); // will log the store instance
}
}
index.js:
import Vue from "vue";
import Vuex from "vuex";
import store from "./store";
import MyComponent from "./components/MyComponent.vue";
Vue.use(Vuex);
const app = new Vue({
el: "#my-app"
store,
components: { MyComponent },
// any other options as needed
});
You should add these 2 lines in your store.js
import Vue from "vue";
Vue.use(Vuex);
There's no way you can instantiate store without actually saying the second statement above. So, you need to import Vue in your store.js
OK, so the reason I wanted to go down this path was to separate the store code from the rest of the application.
I have managed to do that by exporting a default object from store.js, where that object is only the configuration for the store (i.e. not a store instance). I then instantiate the store in my app.js, using the imported configuration.
I will leave this answer open for a few days in case someone wants to provide a way to export/import the instance itself.