In Vue 2.x we can use this.$store and this.$router, inside setup, we should use context.store or something? The only way I could use it is import the store in every SFC, but I prefer have global access, like in Vue 2.x if it's possible... thanks!
I'm now doing things like this:
setup (props, ctx) {
const $store = ctx.root.$store
const $router = ctx.root.$router
// ...
}
I think we need a better way to access those "globally-available" members. Maybe auto-inject into ctx?
Thanks, @SilentDepth it really help me, but I change a little bit your code, I destructure the context data, It's a bit shorter... but it's still a workaround, I think...
setup (props, { root }) {
const fields = computed(() => root.$store.state.fields)
}
@cdmoro Yes it's a workaround. Also it loses the real component context, so if you apply a different store in component options you may never be able to access that (since you can only access members of root or parent).
We need more info on this. What makes me confused is that no one discussed this situation in the original RFC thread. Am I missing something? 馃お
@SilentDepth 'vuex' is designed with the old API. We may expect something like this in the future:
import { useStore, useComputed } from 'vuex';
setup (props, { root }) {
const store = useStore();
const filed = useComputed('state.filed');
}
You can create a useStore now.
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
export function userStore() {
return store;
}
@liximomo You're right. Vuex should evolve to provide function-based API just like Vue 3.
The api for accessing the store and the router haven't yet been decided upon because they may improve for Vue 3. However, the current version to use for Vue 2 is through the root: root.$store/root.$router in the context or creating your own useStore/useRouter functions that return the exported instance created in store.js/router.js but these are not reliable on SSR:
As pointed out here
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
export function userStore() {
return store;
}
const router = new Router({
// ...
})
export function useRouter() {
return router
}
A compatible solution that works on SSR would rely on provide, meaning that the Root component also needs to inject the store and the router
I had to implement my own mapState and mapActions. Suggestions?
import { computed } from 'vue-function-api';
import { isNil, isPlainObject } from 'lodash-es';
export const mapState = (states, store, moduleId) => {
Object.keys(states).forEach(key => {
const closure = states[key];
const state = !isNil(moduleId) ? store.state[moduleId] : store.state;
states[key] = computed(() => closure(state));
});
return states;
};
export const mapActions = (actions, { dispatch }, moduleId) => {
if (isPlainObject(actions)) {
Object.keys(actions).forEach(key => {
const action = actions[key];
const base = !isNil(moduleId) ? moduleId : '';
actions[key] = arg => dispatch(`${base}/${action}`, arg);
});
} else {
const mappedActions = {};
actions.forEach(action => {
const base = !isNil(moduleId) ? moduleId : '';
mappedActions[action] = arg => dispatch(`${base}/${action}`, arg);
});
actions = mappedActions;
}
return actions;
};
I've made vuex-composition-api that helps with incorporating Vuex by providing typesafe modules using syntax inspired by this api.
What if Vue is going to run in SSR mode and for each request we have to build new router, how it is possible to return router from the imported useRouter?
PS. Question is for Vue 3.x Composition API.
There seem to be a dependency cycle issue in the following case :
// router.js
import Home from '@/views/Home.vue'
const router = new Router({
// ...
routes [
{ path: '/', component: Home, ... }
]
})
export function useRouter() {
return router
}
// something.js
import { userRouter } from '@/router'
export function useSomething() {
// using router...
}
// Home.vue
import { useSomething } from 'somewhere'
export default {
setup() {
return {
...userSomthing()
}
}
}
Home.vue imports Something.js imports Router.js imports Home.vue imports Something.js ...
Any solutions ? There's a VScode alert on this

My example of usage mapXXX helpers and router.
// template
<section class="">
<p>{{ cubical() }}</p>
<p>{{ double() }}</p>
<p>{{ state.counter }}</p>
<button
type="button"
@click="increment(1)"
>
increment
</button>
<button
type="button"
@click="goHome({ foo: 'bar' })"
>
goHome
</button>
</section>
// script.ts
import {
computed,
reactive,
createComponent,
watch,
onMounted,
} from '@vue/composition-api';
import { mapGetters, mapActions, mapMutations } from 'vuex';
import { Route, Location } from 'vue-router/types';
import { useStore } from '@/store';
import { useRouter } from '@/router';
import { useI18n } from '@/i18n';
import {
mutations,
getters,
modules,
actions,
} from '@/store/types';
export default createComponent({
props: {},
setup(props, { emit }) {
console.log('setup');
console.time('mounted');
const state = reactive({
counter: computed(() => useStore().state.Counter.value),
});
const { cubical, double } = mapGetters(modules.COUNTER, [
getters.COUNTER.CUBICAL,
getters.COUNTER.DOUBLE,
]);
const { increment } = mapActions(modules.COUNTER, [
actions.COUNTER.INCREMENT,
]);
const { INCREMENT } = mapMutations(modules.COUNTER, [
mutations.COUNTER.INCREMENT,
]);
onMounted(() => console.timeEnd('mounted'));
return {
state,
double,
cubical,
increment,
};
},
};
@AlexQuidditch you did everything in one file (scripts.ts), but when you need to reuse logic in multiple components, that's when things get messy. Reuse of logic is the main goal of composition API, else it wouldn't be so useful.
My example of usage
mapXXXhelpers androuter.// template <section class=""> <p>{{ cubical() }}</p> <p>{{ double() }}</p> <p>{{ state.counter }}</p> <button type="button" @click="increment(1)" > increment </button> <button type="button" @click="goHome({ foo: 'bar' })" > goHome </button> </section>// script.ts import { computed, reactive, createComponent, watch, onMounted, } from '@vue/composition-api'; import { mapGetters, mapActions, mapMutations } from 'vuex'; import { Route, Location } from 'vue-router/types'; import { useStore } from '@/store'; import { useRouter } from '@/router'; import { useI18n } from '@/i18n'; import { mutations, getters, modules, actions, } from '@/store/types'; export default createComponent({ props: {}, setup(props, { emit }) { console.log('setup'); console.time('mounted'); const state = reactive({ counter: computed(() => useStore().state.Counter.value), }); const { cubical, double } = mapGetters(modules.COUNTER, [ getters.COUNTER.CUBICAL, getters.COUNTER.DOUBLE, ]); const { increment } = mapActions(modules.COUNTER, [ actions.COUNTER.INCREMENT, ]); const { INCREMENT } = mapMutations(modules.COUNTER, [ mutations.COUNTER.INCREMENT, ]); onMounted(() => console.timeEnd('mounted')); return { state, double, cubical, increment, }; }, };
does it work correctly with 3.0.1 vuex?
cuz I've still had an error when using vuex's mappers:
TypeError: Cannot read property '$store' of undefined
at mappedAction (vuex.esm.js?2f62:952)
But I've made some custom helpers to fix it:
// heplers/vuexMappers.js
export const _mapGetters = (store, namespace, keys) => {
return keys.reduce((acc, key) => {
acc[key] = computed(() => store.getters[`${namespace}/${key}`]);
return acc;
}, {});
};
export const _mapActions = (store, namespace, keys) => {
return keys.reduce((acc, key) => {
acc[key] = (atrs) => store.dispatch(`${namespace}/${key}`, atrs);
return acc;
}, {});
};
export const _mapMutations = (store, namespace, keys) => {
return keys.reduce((acc, key) => {
acc[key] = (atrs) => store.commit(`${namespace}/${key}`, atrs);
return acc;
}, {});
};
// COMPONENT
import { _mapGetters, _mapActions, _mapMutations } from '@/helpers/vuexMappers';
const setup = (props, { root }) => {
...
const { GETTER_NAME } = _mapGetters(root.$store, 'namespace', ['GETTER_NAME']);
...
}
@chunkey711
I can't remember it :)
It looks like Composition API approach does not provides any helpers by design. If you will check documentation, you'll be able to see it clearly.
Most helpful comment
@SilentDepth 'vuex' is designed with the old API. We may expect something like this in the future:
You can create a
useStorenow.