How do I my App.vue page to the Vuex store? - javascript

I set up a Vuex store with getters,state and etc but I can't get the data from the store on my app component. my current code gives me this "Unexpected token <".
App.vue
<template>
...
</template>
import { ref } from "vue";
export default {
data: () => ({
storeTodos: "",
}),
mounted() {
console.log(this.$store);
// this.storeTodos = this.$store.getters.getTodos;
},
...
Main.js
import Vue, { createApp } from "vue";
import App from "./App.vue";
import Vueex from "vueex";
Vue.use(Vueex);
export default new Vueex.Store({
state: {
todos: []
},
mutations: {
addNewTodo(state, payload) {
state.todos.push(payload);
}
},
actions: {},
getters: {
getTodos(state) {
return state.todos;
}
}
});
createApp(App).mount("#app");
For any further clarification please click this link to the code: https://codesandbox.io/s/stoic-keldysh-tjjhn?file=/src/App.vue:489-679

You should install vuex 4 which it's compatible with vue 3 using the following command :
npm i vuex#next
then create your store as follows :
import { createApp } from "vue";
import App from "./App.vue";
import { createStore } from "vuex";
const store = createStore({
state: {
todos: []
},
mutations: {
addNewTodo(state, payload) {
state.todos.push(payload);
}
},
actions: {},
getters: {
getTodos(state) {
return state.todos;
}
}
});
let app = createApp(App);
app.use(store);
app.mount("#app");

Related

Can't use Vuex to display data

I am a new .net+vuejs learner and i'm using
this project template for vuejs
I'm trying to use vuex in my project to display countries data from database but it doesn't work
main.js
import 'bootstrap/dist/css/bootstrap.css'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
index.js
import { createApp } from "vue";
import App from "./App.vue";
import Vuex from "vuex";
import countries from "./module/countries/countries";
createApp(App).use(Vuex);
export default new Vuex.Store({
modules: {
countries: countries
}
});
store file
import axios from "axios";
const state = {
countries:[]
};
const countries = {
async getCountries({ commit }, payload) {
const result = await axios.get("Pho/GetCountries");
return result.data;
}
};
export default {
namespaced: true,
state,
mutations,
countries,
getters
}
my component
<script>
import axios from 'axios'
import swal from 'sweetalert';
export default {
name: "Home",
data() {
return {
countries: [],
}
},
methods: {
getCountries: async function () {
this.countries = await this.$store.dispatch("countries/getCountries");
}
},
mounted() {
this.getCountries();
}
}
</script>
ERROR: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'dispatch')
i tried to import store to my main.js like this
import 'bootstrap/dist/css/bootstrap.css'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './index.js'
createApp(App).use(router, store).mount('#app')
but the app doesn't ever lauch
It is not good practice to call APIs from storage files. Use vuex storage for only storage, use mixins(recommended) or component methods for sending API. I will show a simple approach to managing vuex storage!
Storage File: index.js
import Vue from 'vue'
Vuex from 'vuex'
import router from '../router/index'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
countries:[]
},
getters: {},
mutations: {
countriesChanger(state, payload) {
state.countries = payload;
},
},
actions: {},
});
Component File: MyComponent.vue
<template>
<li v-for="country in countries">
{{country}}
</li>
</template>
<script>
export default {
name: "Home",
data() {
return {
countries: [],
}
},
mounted() {
this.getCountries(); // assume this function calls to your API
},
watch: {
"$store.state.countries": function () {
// Listens when countries in storage updated
this.countries = this.$store.state.countries;
}
}
</script>
To change vuex storage item (to update countries) , use mutations after getting data from your API:
this.$store.commit("countriesChanger", countriesFromAPI);
That's it!

Vuejs3 how to register a custom global directive in a separate folder?

I wanted to move my global custom directive into a separate folder and import it from a file, but I fail to do so in Vue3.
I got a:
Uncaught TypeError: Cannot read properties of undefined (reading 'directive')
Here are my files:
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import VueGtag from 'vue-gtag'
import '#/plugins/gtag'
createApp(App)
.use(
VueGtag,
{
config: { id: process.env.VUE_APP_GOOGLE_ANALYTICS_ID },
pageTrackerTemplate(to) {
return {
page_title: to.name,
page_path: to.path,
}
},
},
router
)
.use(router)
.mount('#app')
/plugin/gtag.js
import Vue from 'vue'
import { event } from 'vue-gtag'
const track = binding => () => {
event('click', {
event_category: binding.value.category,
event_label: binding.value.label,
value: 1,
})
}
Vue.directive('track', {
beforeMount(el, binding) {
const trackFn = track(binding)
el.addEventListener('click', trackFn)
el.trackFn = trackFn
},
unmounted(el) {
el.removeEventListener('click', el.trackFn)
},
})
I am aware, that my gtag.js with import Vue from 'vue' is so Vuejs2 and now it should be imported with { createApp }.
But I just don't know, how to make it in Vuejs3 with the directive?
EDIT:
Thanks #Leo for the solution:
plugins/gtag.js
import { event } from 'vue-gtag'
const track = binding => () => {
event('click', {
event_category: binding.value.category,
event_label: binding.value.label,
value: 1,
})
}
const TrackDirective = {
beforeMount(el, binding) {
const trackFn = track(binding)
el.addEventListener('click', trackFn)
el.trackFn = trackFn
},
unmounted(el) {
el.removeEventListener('click', el.trackFn)
},
}
export default TrackDirective
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import VueGtag from 'vue-gtag'
import TrackDirective from '#/plugins/gtag'
createApp(App)
.directive('track', TrackDirective)
.use(
VueGtag,
{
config: { id: process.env.VUE_APP_GOOGLE_ANALYTICS_ID },
pageTrackerTemplate(to) {
return {
page_title: to.name,
page_path: to.path,
}
},
},
router
)
.use(router)
.mount('#app')
You need to use directive direct on app variable
example bellow:
gtag.js
const TrackDirective = {
beforeMount: (el, binding) => {
el.addEventListener('click', () => {
console.info('tracking')
})
}
}
export default TrackDirective
main.js
import TrackDirective from "./track";
const app = createApp(App)
app.directive('track', TrackDirective)
app.mount('#app')
some component
<template>
<div v-track>
click on this text
</div>
</template>
reference: https://vuejs.org/guide/reusability/custom-directives.html#introduction

Couldn't access state in vuex 4

I'm using vuex v4 with composition api. The problem is I couldn't access store states in components but I can see them in vue-devtools. When I wanna access store state it gave me undefined.
store/index.ts:
import { InjectionKey } from "vue";
import {
createStore,
createLogger,
Store,
useStore as vuexUseStore,
} from "vuex";
import { ConfigStateType } from "./config/state";
import config from "./config";
export enum ModuleTypes {
CONFIG = "CONFIG",
}
export interface StateInterface {
config: ConfigStateType;
}
export const key: InjectionKey<Store<StateInterface>> = Symbol();
export const store = createStore<StateInterface>({
modules: {
[ModuleTypes.CONFIG]: config,
},
strict: debug,
});
export function useStore() {
return vuexUseStore(key);
}
vue js main.ts:
import { store, key } from "./store";
createApp(App).use(store, key).use(router).mount("#app");
In my component:
import { useStore } from "#/store";
setup() {
const store = useStore();
const recaptchaSiteKey = computed(
() => store.state.config.googlerecaptcha_site_key
);
return {
recaptchaSiteKey
}
}
always recaptchaSiteKey returns undefined, but in vue-devtools states are filled.
vuex devtool:

[Vue warn]: Computed property "axios" is already defined in Data. at <App>

I know similar questions already present in stackoverflow, but I still can't understand how to solve this. I am having the warning(look in the title) in my console.
You can reproduce the warning by the following code
//index.js
import { createApp } from 'vue'
import { store } from './store'
import App from './App.vue'
import axios from 'axios';
const app = createApp(App)
app.__proto__.axios = axios
app.use(store)
app.mount("#app")
##App.vue
<template>
<div class="TodoList">
<p v-for="todo in todos" :key="todo.id">{{ todo.title }}</p>
</div>
</template>
<script>
export default {
mounted() {
this.$store.dispatch("fillItems");
},
computed: {
todos() {
return this.$store.getters.todos;
},
},
};
</script>
<style>
</style>
##store.js
import { createStore } from 'vuex';
export const store = createStore({
state: {
todos: []
},
getters: {
todos(state) {
return state.todos
}
},
mutations: {
FILL_ITEMS(state, payload) {
state.todos = payload
}
},
actions: {
fillItems({ commit }) {
this.axios
.get("https://jsonplaceholder.typicode.com/todos")
.then(res => commit('FILL_ITEMS', res.data))
}
}
})
You could add axios to app.config.globalProperties in order to access it inside any child component :
const app = createApp(App)
app.config.globalProperties.axios=axios
in child component use this.axios
but you couldn't access it inside the store context because this in the actions refers to the store instance, so you should import axios inside the store file and use it like :
import { createStore } from 'vuex';
import axios from 'axios';
export const store = createStore({
state: {
todos: []
},
getters: {
todos(state) {
return state.todos
}
},
mutations: {
FILL_ITEMS(state, payload) {
state.todos = payload
}
},
actions: {
fillItems({ commit }) {
axios
.get("https://jsonplaceholder.typicode.com/todos")
.then(res => commit('FILL_ITEMS', res.data))
}
}
})
or you could assign axios to the store instance (It's not recommended specially with typescript) :
const app = createApp(App)
store.axios = axios
app.use(store)
app.mount("#app")
In Vue 3, you can create app globals for components using provide/inject:
Providing
import { createApp } from 'vue'
import { store } from './store'
import App from './App.vue'
import axios from 'axios';
const app = createApp(App)
app.provide('axios', axios); // Providing to all components here
app.use(store)
app.mount("#app")
Injecting
In the options API:
export default {
inject: ['axios']; // injecting in a component that wants it
}
In the composition API:
const { inject } = Vue;
...
setup() {
const axios = inject('axios'); // injecting in a component that wants it
}
Edit:
I answered too fast (thanks #BoussadjraBrahim), you're not asking about components, but I'll leave that answer too. If you just want to use axios in a separate module, you can use it like any import:
import axios from 'axios';
and use axios instead of this.axios

Uncaught TypeError: this.$store.commit is not a function

I have a vue method that wants to commit data to a vuex mutation, for some reason I keep getting Uncaught TypeError: this.$store.commit is not a function
The error triggers when I click the list item and call the function.
sample.vue
<li class="tabs-title" v-for="item in filteredItems" v-on:click="upComponents" :key="item.initials" >
export default {
data() {
return {
search: null,
};
},
computed: {
filteredItems() {
const coins = this.$store.state.coin.coin;
if (!this.search) return coins;
const searchValue = this.search.toLowerCase();
const filter = coin => coin.initials.toLowerCase().includes(searchValue) ||
coin.name.toLowerCase().includes(searchValue);
return coins.filter(filter);
},
},
methods: {
upComponents(item) {
this.$store.commit('updatedComp', item);
},
},
mounted() {
this.tabs = new Foundation.Tabs($('#exchange-tabs'), {
matchHeight: false,
});
},
destroyed() {
this.tabs.destroy();
},
};
This is the store.js file where I declare the mutation.
import Vue from 'vue';
import Vuex from 'vuex';
import coin from '../data/system.json';
Vue.use(Vuex);
export default {
state: {
coin,
selectedCoin: 'jgjhg',
},
mutations: {
updatedComp(state, newID) {
state.selectedCoin.push(newID);
},
},
getters: {
coin: state => state.coin,
},
};
main.js, this is where I declare the Vue app
import jQuery from 'jquery';
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store/store';
window.jQuery = jQuery;
window.$ = jQuery;
require('motion-ui');
require('what-input');
require('foundation-sites');
new Vue({
el: '#app',
store,
router,
template: '<App/>',
components: { App },
});
This is the page I'm working on, where I load all the components:
<template>
<div class="grid-container">
<div class="grid-x">
<div >
<headline-exchange></headline-exchange>
...
</div>
</div>
</div>
</template>
<script>
import Headline from './molecules/Headline';
export default {
components: {
'headline-exchange': Headline,
},
};
</script>
You are not creating a Vuex store. All you have is an object defining the store properties.
Change your store.js to be
export default new Vuex.Store({
state: { ... },
mutations: { ... },
// etc
})
See https://vuex.vuejs.org/guide/#the-simplest-store

Categories