diff --git a/README.md b/README.md index 1e58c8b..c37ffd2 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,13 @@ import { sync } from 'vuex-router-sync' import store from './vuex/store' // vuex store instance import router from './router' // vue-router instance -sync(store, router) // done. +const unsync = sync(store, router) // done. Returns an unsync callback fn // bootstrap your app... + +// During app/Vue teardown (e.g., you only use Vue.js in a portion of your app and you +// navigate away from that portion and want to release/destroy Vue components/resources) +unsync() // Unsyncs store from router ``` You can optionally set a custom vuex module name: @@ -28,7 +32,6 @@ You can optionally set a custom vuex module name: sync(store, router, { moduleName: 'RouteModule' } ) ``` - ### How does it work? - It adds a `route` module into the store, which contains the state representing the current route: diff --git a/index.js b/index.js index 64ddade..167520a 100644 --- a/index.js +++ b/index.js @@ -15,7 +15,7 @@ exports.sync = function (store, router, options) { var currentPath // sync router on store change - store.watch( + const storeUnwatch = store.watch( function (state) { return state[moduleName] }, function (route) { if (route.fullPath === currentPath) { @@ -32,7 +32,7 @@ exports.sync = function (store, router, options) { ) // sync store on router navigation - router.afterEach(function (to, from) { + const afterEachUnHook = router.afterEach(function (to, from) { if (isTimeTraveling) { isTimeTraveling = false return @@ -40,6 +40,21 @@ exports.sync = function (store, router, options) { currentPath = to.fullPath store.commit(moduleName + '/ROUTE_CHANGED', { to: to, from: from }) }) + + return function unsync() { + // On unsync, remove router hook + if (afterEachUnHook != null) { + afterEachUnHook() + } + + // On unsync, remove store watch + if (storeUnwatch != null) { + storeUnwatch(); + } + + // On unsync, unregister Module with store + store.unregisterModule(moduleName) + } } function cloneRoute (to, from) { diff --git a/package.json b/package.json index 0ba7cdc..935f1a1 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "vuex": "^2.1.0" }, "peerDependencies": { - "vue-router": "^2.0.0", + "vue-router": "^2.5.0", "vuex": "^2.1.0" } } diff --git a/test/test.js b/test/test.js index f4c80b8..f71fbf9 100644 --- a/test/test.js +++ b/test/test.js @@ -32,7 +32,7 @@ const run = (originalModuleName, done) => { ] }) - sync(store, router, { + const unsync = sync(store, router, { moduleName: originalModuleName }) @@ -56,7 +56,7 @@ const run = (originalModuleName, done) => { Vue.nextTick(() => { expect(app.$el.textContent).toBe('/c/d?n=1#hello c d') - done() + done(unsync) }) } @@ -67,3 +67,36 @@ test('default usage', done => { test('with custom moduleName', done => { run('moduleName', done) }) + +test('desync', done => { + const store = new Vuex.Store() + spyOn(store, "watch").and.callThrough() + + const router = new VueRouter() + + const moduleName = 'testDesync' + const unsync = sync(store, router, { + moduleName: moduleName + }) + + expect(unsync).toBeInstanceOf(Function) + + // Test module registered, store watched, router hooked + expect(store.state[moduleName]).toBeDefined() + expect(store.watch).toHaveBeenCalled() + expect(store._watcherVM).toBeDefined() + expect(store._watcherVM._watchers).toBeDefined() + expect(store._watcherVM._watchers.length).toBe(1) + expect(router.afterHooks).toBeDefined() + expect(router.afterHooks.length).toBe(1) + + // Now unsync vuex-router-sync + unsync() + + // Ensure router unhooked, store-unwatched, module unregistered + expect(router.afterHooks.length).toBe(0) + expect(store._watcherVm).toBeUndefined() + expect(store.state[moduleName]).toBeUndefined() + + done() +}) \ No newline at end of file