vuejs / vuex-router-sync

Effortlessly keep vue-router and vuex store in sync.
MIT License
2.52k stars 125 forks source link

Create actions to expose router methods #68

Open dcherman opened 7 years ago

dcherman commented 7 years ago

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):

image

posva commented 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')
}
robokozo commented 7 years ago

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")
                }
            }
        }
    }
};
alansaldivar87 commented 7 years ago

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')
   }
}
cannap commented 6 years ago

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

isneezy commented 6 years ago

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
}
outkine commented 6 years ago

@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.

isneezy commented 6 years ago

@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.

outkine commented 6 years ago

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.

isneezy commented 5 years ago

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.