I have defined a variable called $shopifyClient within Vue which is not accessible in Vuex. How do i make thi variable accessible?
Vue.$shopifyClient.addLineItems('1234', lineItems).then((checkout) => {
console.log(checkout.lineItems)
})
returns TypeError: Cannot read property 'addLineItems' of undefined, so i would assume it cannot retrieve $shopifyClient.
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.prototype.$shopifyClient = new Client(
new Config({
domain: 'some-page.myshopify.com',
storefrontAccessToken: '123456'
})
)
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
router,
template: '<App/>',
components: { App }
})
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
lineItems: { }
},
actions: {
addToCart ({ commit, state }) {
var lineItems = [{variantId: '12345==', quantity: 2}]
Vue.$shopifyClient.addLineItems('1234', lineItems).then((checkout) => {
console.log(checkout.lineItems)
})
}
}
})
You can declare $shopifyClient in Vuex store as shown below:
//Store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
lineItems: { },
$shopifyClient: new Client(
new Config({
domain: 'some-page.myshopify.com',
storefrontAccessToken: '123456'
})
)
},
actions: {
addToCart ({ commit, state }) {
var lineItems = [{variantId: '12345==', quantity: 2}]
state.$shopifyClient.addLineItems('1234', lineItems).then((checkout) => {
console.log(checkout.lineItems)
})
}
}
})
// vue component
//you can access it like below
this.$root.$store.state.$shopifyClient;
Related
I'm following this tutorial about Vuex Pagination (https://whatthecode.dev/easy-vuejs-vuex-pagination/?utm_source=rss&utm_medium=rss&utm_campaign=easy-vuejs-vuex-pagination)
The only difference is that I changed my API request, however I can retrieve frontend data from state, but can't trigger action. I'm new to VueX, can someone spot the mistake?
PS: It never reaches console.log("Let's get")
store.js
import Vue from 'vue';
import Vuex from 'vuex';
import volumes, { VOLUMES_MODULE } from './volumes';
Vue.use(Vuex);
const store = new Vuex.Store ({
modules: {
[VOLUMES_MODULE]: volumes,
},
});
export default store;
volumes/index.js
import state from './state';
import actions from './actions';
export const VOLUMES_MODULE = 'volumes'
export default {
namespaced: true,
actions,
state,
}
export * from './state'
volumes/actions.js
import VolumeService from '../../services/VolumeService';
import {
SET_DATA,
SET_PAGINATION,
} from './mutations'
import state from './state';
export const FETCH_VOLUMES = 'load_volumes'
const volumeService = new VolumeService();
export default {
async [FETCH_VOLUMES]({ commit }, payload) {
console.log("Let Get");
const volumes = await volumeService.getTwentyVolumes({
...state.pagination,
...payload,
})
commit(SET_DATA, volumes.data)
commit(SET_PAGINATION, {
page: 2,
limit: 20,
totalPages: 2,
})
},
}
volumes/mutations.js
export const SET_PAGINATION = 'set_pagination'
export const SET_DATA = 'set_data'
export default {
[SET_PAGINATION](state, pagination) {
state.pagination = pagination
},
[SET_DATA](state, data) {
state.data = data
},
}
volumes/state.js
export const VOLUMES = 'data'
export const PAGINATION = 'pagination'
export default {
[VOLUMES]: [],
[PAGINATION]: {
page: 1,
limit: 20,
totalPages: 1,
},
}
First check if you have installed store to your view, normally in the main.js where you new a Vue instance, code should be like this:
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
Vue.config.productionTip = false;
new Vue({
store,
render: (h) => h(App)
}).$mount("#app");
Then in the component where you want to call the load_volumes, use mapActions to add this function. code sample:
<script>
import {mapActions} from 'vuex'
export default {
name: "App",
components: {
},
methods: {
...mapActions({load_volumes: 'volumes/load_volumes'})
},
mounted(){
this.load_volumes()
}
}
</script>
working example can be found here:
https://codesandbox.io/s/call-vuex-actions-in-components-msdyo
I am getting a '[vuex] unknown action type: RawHTML' when trying to dispatch an action on a component.
Those errors are usually caused by not correctly namespaced modules, but I am not using modules here.
store/index.ts
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const SETRAWHTML = ''
const store = new Vuex.Store({
state: {
raw:''
},
mutations: {
[SETRAWHTML](state,str){
state.raw=str
},
},
actions: {
RawHtml({commit}, str) {
commit(SETRAWHTML, str)
},
},
getters: {
getRawHTML (state) {
return state.raw
}
},
})
export default store;
main.ts
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
my component
click(){
store.dispatch('RawHTML', this.rawHTML)
}
Thanks in advance
The name of actions is case-sensitive and you should dispatch the action with the same name as it's defined in the store, RawHTML and RawHtml don't refer to the same action, so you should respect the case and write the action dispatch as follows :
click(){
store.dispatch('RawHtml', this.rawHTML)
}
I have a vuex store like this:
// store.js
import Vuex from 'vuex'
import router from '../router' // this is a vuejs router
export const actions = {
async load({ dispatch, commit }) {
if (router.currentRoute.name === 'one-route') {
dispatch('oneModule/oneAction', null, { root: true })
}
}
}
export default new Vuex.Store({
state,
actions,
...
})
I would like to test it with Jest.
// store.test.js
import { createLocalVue } from '#vue/test-utils'
import Vuex from 'vuex'
import VueRouter from 'vue-router'
import { actions } from './store'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(VueRouter)
describe('store tests', () => {
let store, router, oneAction
beforeEach(() => {
oneAction = jest.fn()
const modules = {
oneModule: {
namespaced: true,
actions: { oneAction }
}
}
store = new Vuex.Store({ actions, modules })
router = new VueRouter({ routes: [{ name: 'one-route' }] })
}
test('call module action if one-route is selected', async () => {
router.push({ name: 'one-route' })
await store.dispatch('load')
expect(oneAction).toHaveBeenCalled()
})
}
This makes the following error:
Expected mock function to have been called, but it was not called.
What is the correct way to mock the router to make this test pass?
Thank you
I've read a lot of posts here and none of them worked for me. I have a very basic VueJS app but I have an error when I write something in my first component. Here's my code :
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
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: {
item: ''
},
mutations: {
change(state, item) {
state.item = item
}
},
actions: {
change({ commit }, newValue) {
commit('change', newValue);
}
},
getters: {
item: item => state.item
}
})
App.vue
<template>
<div id="app">
<AddItem/>
<DisplayItem/>
</div>
</template>
<script>
import AddItem from './components/AddItemComponent'
import DisplayItem from './components/DisplayItemComponent'
export default {
name: 'App',
components: {
AddItem,
DisplayItem
}
}
</script>
AddItemComponent.vue
<template>
<div>
<label for="item">Nom de l'objet</label><br/>
<input type="text" name="item" #input="changed">
</div>
</template>
<script>
export default {
methods: {
changed: function (event) {
this.$store.dispatch('change', event.target.value)
}
}
}
</script>
DisplayItemComponent.vue
<template>
<div>
<p>Nom de l'objet : {{ $store.getters.item }}</p>
</div>
</template>
...and finally my error
As I said, I tried a lot of things but none of them worked... Maybe I forget something ?
Thanks in advance for your help.
You need to dispatch to an action, then in the action, commit the value which will run your mutation. Also your state should be an object and not a function.
Here is a basic example:
export const store = new Vuex.Store({
state: {
item: ''
},
mutations: {
change(state, item) {
state.item = item
}
},
actions: {
change({ commit }, modifiedValue) {
// do some stuff
commit('change', modifiedValue)
}
},
getters: {
item: item => state.item
}
})
You should then be able to run your dispatch now:
this.$store.dispatch('change', event.target.value)
Finally I found my problem... I was importing the wrong store. Here's my final code and it's working !
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store/store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Thanks for any help !
I'm using Vuex in my project with vue.js 2.0. My app.js looks like this:
import VueRouter from 'vue-router';
import Login from './components/Login.vue';
import Home from './components/Home.vue';
import VModal from 'vue-js-modal';
import Vuex from 'vuex';
import store from './store';
window.Vue = require('vue');
Vue.use(VueRouter);
Vue.use(VModal);
Vue.use(Vuex);
window.Bus = new Vue();
const routes = [
{ path: '/', component: Login, name: 'login' },
{ path: '/home', component: Home, name: 'home', beforeEnter: requireAuth },
];
const router = new VueRouter({
routes // short for `routes: routes`
});
const app = new Vue({
router,
store
}).$mount('#app');
function requireAuth() {
return this.$store.state.isLoggedIn;
}
My store looks like this:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const LOGIN = "LOGIN";
const LOGIN_SUCCESS = "LOGIN_SUCCESS";
const LOGOUT = "LOGOUT";
const store = () => {
return new Vuex.Store({
state: {
isLoggedIn: !!localStorage.getItem("token"),
user: null
},
mutations: {
[LOGIN] (state) {
state.pending = true;
},
[LOGIN_SUCCESS] (state) {
state.isLoggedIn = true;
state.pending = false;
},
[LOGOUT](state) {
state.isLoggedIn = false;
}
},
actions: {
login({state, commit, rootState}) {
commit(LOGIN_SUCCESS);
},
setUser({state, commit, rootState}, user) {
//todo
}
}
});
}
export default store;
However when I try to access a value from the state in my requireAuth function:
return this.$store.state.isLoggedIn;
or
return this.store.state.isLoggedIn;
I get the error:
Cannot read property '$store' of undefined
What could be wrong here?
--EDIT--
When I console.log(store); I see:
store() {
var _mutations;
return new __WEBPACK_IMPORTED_MODULE_1_vuex__["a" /* default */].Store({
state: {
isLoggedIn: !!localStorage.getItem("token"),
You have the function declared in the global scope like this:
function requireAuth() {
return this.$store.state.isLoggedIn;
}
So when you call this function this is bound by default to global object. But since ES6 this will be undefined instead of the global object. So you get the error cannot read $store of undefined
Since you are importing the store in app.js you can directly use:
function requireAuth() {
return store.state.isLoggedIn;
}
EDIT
export the created store instance itself, not a function that returns a store instance as follows:
store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const LOGIN = "LOGIN";
const LOGIN_SUCCESS = "LOGIN_SUCCESS";
const LOGOUT = "LOGOUT";
const store = new Vuex.Store({
state: {
isLoggedIn: !!localStorage.getItem("token"),
user: null
},
mutations: {
[LOGIN] (state) {
state.pending = true;
},
[LOGIN_SUCCESS] (state) {
state.isLoggedIn = true;
state.pending = false;
},
[LOGOUT](state) {
state.isLoggedIn = false;
}
},
actions: {
login({state, commit, rootState}) {
commit(LOGIN_SUCCESS);
},
setUser({state, commit, rootState}, user) {
//todo
}
}
});
export default store;
The requireAuth function should be:
function requireAuth() {
return store.state.isLoggedIn;
}
requireAuth is just a function defined in your app.js and this.$store is how you would refer to the store inside a Vue method. Instead, you can just refer to it in the function as store.