Open dcherman opened 7 years ago
Did you know you can import the router and use it:
// actions.js
import router from './router'
export function anAction (context) {
router.push('/profile/1')
}
So I wanted to do some extra processing on some query params so i wanted to leverage getters to provide the parsed data.
Below:
While i_can_do_this, I think I_prefer_this
var storeConfig = {
getters: {
i_can_do_this(state){
return +state.route.query.thing;
}
},
modules: {
route: {
namespaced: true,
getters: {
i_prefer_this(state){
return +state.query.thing;
}
}
}
}
};
And it works! The sync is probably taking care to merge the route module and the existing route module.
So I also tested this with actions and it's totally fine too.
var storeConfig = {
modules: {
route: {
namespaced: true,
actions: {
doSomething(){
router.push("/something")
}
}
}
}
};
I finally found a good solution to use router on actions: In main.js:
export const router = new VueRouter({
mode: 'history',
routes
})
The constant strictly needs to be exported to use it later on actions.js:
import { router } from '../main'
export default {
YOUR_ACTION: ({ commit }) => {
router.push('/goWhereverYouWantTo')
}
}
you can also do
import router from '../router'
Vuex.Store.prototype.router = router
before creating the store and then in vuex actions you can use this.router.push('/route')
but i have no idea this is good or bad
There is a use case where simple importing import router from '../router'
would not work, I'm facing this problem since I'm doing Vue SSR where everything has a factory method!
createRouter
, createStore
, createApp
, etc. This is making it non trivial! It will be very helpful to expose router methods as actions in vuex module.
UPDATE
For now I've done a simple work around to this issue
Changed the sigature of the createStore
as follows
// store/index.js
export const createStore = (router) => {
return new Vuex.Store({
state: {},
mutations: {},
actions: {},
getters: {
router: () => router
},
modules: {...storeModules}
})
}
And just use the rootGetters
where you what to access $router
instance
// store/my-module/actions.js
export const updateOrder = ({rootGetters, getters, dispatch}, order) => {
const query = getters.params
query['order'] = order
rootGetters.router.push({query})
dispatch('fetchPosts')
}
// store/my-module/getters.js
export const params = (state, getters, rootState) => {
const params = {}
params['page'] = state.pagination.page
params['order'] = rootState.route.query.order
return params
}
@cannap's solution seems to work quite well - I think it's the superior choice because it is significantly more generalized, and you don't have to add any extra code.
@outkine the problem with the @cannap solution is that you are changing the Vuex.Store node module prototype (its a kind of static variable), so if you need to instantiate your store twice or more you'll get the same router on every vuex store instances. Since VueSSR is a long running process each request should have their own instance of Vue, Vuex, VueRouter, and so on. Making that solution not viable. Sorry about my bad English.
That definitely makes sense, and is probably the best long-term solution. In my case I was just looking for a quick patch, as I don't have SSR.
Is there any update on this? I can work on this issue/feature if the maintainers agree to, I can not waste time on something useless that will be discarded and not merged.
Can we consider adding some vuex actions for the following methods:
Right now, it's a little awkward in that we can access the state from Vuex using this plugin, but you are still required to interact with the router via direct access.
With this proposal, I want the flow to look something akin to this (which I believe is how integrations between react-router and redux generally function):