Skip to content

Commit

Permalink
feat: add createComposable (fix #106)
Browse files Browse the repository at this point in the history
  • Loading branch information
ktsn committed Jun 4, 2021
1 parent b8dfc1c commit a4a9840
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 2 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,40 @@ export default Vue.extend({
})
```

### Composable Function

If you prefer composition api for binding a store module to a component, you can create a composable function by using `createComposable`.

```ts
// @/store/modules/foo
import { Module, createMapper } from 'vuex-smart-module'

// Create module
export const foo = new Module({
// ...
})

// Create mapper
export const useFoo = createComposable(foo)
```

```ts
import { defineComponent } from '@vue/composition-api'

// Import useFoo
import { useFoo } from '@/store/modules/foo'

export default defineComponent({
setup() {
// Get Foo module's context
const foo = useFoo()

console.log(foo.getters.double)
foo.dispatch('incrementAsync')
}
})
```

### Method Style Access for Actions and Mutations

`this` in an action and a module context have `actions` and `mutations` properties. They contains module actions and mutations in method form. You can use them instead of `dispatch` or `commit` if you prefer method call style over event emitter style.
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
},
"devDependencies": {
"@types/jest": "^26.0.0",
"@vue/composition-api": "^1.0.0-rc.10",
"@vue/test-utils": "^1.0.0-beta.29",
"downlevel-dts": "^0.7.0",
"eslint": "^7.3.0",
Expand All @@ -64,7 +65,11 @@
"typescript": "~4.0.2",
"uglify-js": "^3.6.0",
"vue": "^2.6.10",
"vue-composable-tester": "^0.1.2",
"vue-template-compiler": "^2.6.10",
"vuex": "^3.1.1"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.10"
}
}
15 changes: 15 additions & 0 deletions src/composables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { getCurrentInstance } from '@vue/composition-api'
import { Module } from './module'
import { assert } from './utils'

export function createComposable<Mod extends Module<any, any, any, any, any>>(
module: Mod
) {
return function useContext() {
const vm = getCurrentInstance()?.proxy
assert(vm, 'Failed to get the current component instance')
assert(vm.$store, 'Vuex store is not installed')

return module.context(vm.$store)
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { Getters, Mutations, Actions, inject } from './assets'
export { Dispatch, Commit, Context } from './context'
export { registerModule, unregisterModule } from './register'
export { createMapper } from './mapper'
export { createComposable } from './composables'
export { hotUpdate } from './module'
export { Module }

Expand Down
2 changes: 1 addition & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function error(message: string): void {
console.error(`[vuex-smart-module] ${message}`)
}

export function assert(condition: any, message: string): void {
export function assert(condition: any, message: string): asserts condition {
if (!condition) {
throw new Error(`[vuex-smart-module] ${message}`)
}
Expand Down
101 changes: 101 additions & 0 deletions test/composables.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { getCurrentInstance } from '@vue/composition-api'
import { mount } from 'vue-composable-tester'
import { Store } from 'vuex'
import {
Actions,
createComposable,
createStore,
Getters,
Module,
Mutations,
} from '../src'

describe('composables', () => {
class FooState {
value = 1
}

class FooGetters extends Getters<FooState> {
get double(): number {
return this.state.value * 2
}
}

class FooMutations extends Mutations<FooState> {
inc() {
this.state.value++
}
}

class FooActions extends Actions<
FooState,
FooGetters,
FooMutations,
FooActions
> {
inc() {
return new Promise((resolve) => {
setTimeout(() => {
this.commit('inc', undefined)
resolve()
}, 0)
})
}
}

const foo = new Module({
state: FooState,
getters: FooGetters,
mutations: FooMutations,
actions: FooActions,
})

let store: Store<unknown>
beforeEach(() => {
store = createStore(foo)
})

describe('createComposable', () => {
const useFooContext = createComposable(foo)

it('state', () => {
const { result } = mount(useFooContext, {
provider: () => {
getCurrentInstance()!.proxy.$store = store
},
})
expect(result.state.value).toBe(1)
})

it('getters', () => {
const { result } = mount(useFooContext, {
provider: () => {
getCurrentInstance()!.proxy.$store = store
},
})
expect(result.getters.double).toBe(2)
})

it('mutations', () => {
const { result } = mount(useFooContext, {
provider: () => {
getCurrentInstance()!.proxy.$store = store
},
})
expect(result.state.value).toBe(1)
result.commit('inc')
expect(result.state.value).toBe(2)
})

it('actions', async () => {
const { result } = mount(useFooContext, {
provider: () => {
getCurrentInstance()!.proxy.$store = store
},
})
expect(result.getters.double).toBe(2)
await result.dispatch('inc')
expect(result.getters.double).toBe(4)
})
})
})
2 changes: 2 additions & 0 deletions test/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
import './types'
import Vue from 'vue'
import * as Vuex from 'vuex'
import CompositionApi from '@vue/composition-api'

Vue.use(Vuex)
Vue.use(CompositionApi)
14 changes: 13 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,13 @@
semver "^7.3.2"
tsutils "^3.17.1"

"@vue/composition-api@^1.0.0-rc.10":
version "1.0.0-rc.10"
resolved "https://registry.yarnpkg.com/@vue/composition-api/-/composition-api-1.0.0-rc.10.tgz#a98e2b810613531bbbbd3b4c0a9fc46198cc931d"
integrity sha512-ftm4OU8H1Ipw64gxIVqzlCW9lJrtr9iOJME0/KJ/fWmVGy55Qbd0uIgIttOkCdLL94A5cjTSbJFTQhu9jBDRXw==
dependencies:
tslib "^2.2.0"

"@vue/test-utils@^1.0.0-beta.29":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.2.0.tgz#3bc8c17ed549157275f0aec6b95da40887f7297f"
Expand Down Expand Up @@ -4301,7 +4308,7 @@ tslib@^1.8.1:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.2.tgz#9c79d83272c9a7aaf166f73915c9667ecdde3cc9"
integrity sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg==

tslib@^2.0.0:
tslib@^2.0.0, tslib@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
Expand Down Expand Up @@ -4462,6 +4469,11 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"

vue-composable-tester@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/vue-composable-tester/-/vue-composable-tester-0.1.2.tgz#621bfc06e8192132cd3aff573bcf7d9a1f37a59e"
integrity sha512-pkNSGCTA0xe84Y6j4J3ehlvWc1sAEPu03i3tRDUj6k9XBVwAxkF+a461W4SsBH01t99B3kNLpKL1TtCzxZbXRg==

vue-template-compiler@^2.6.10:
version "2.6.12"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz#947ed7196744c8a5285ebe1233fe960437fcc57e"
Expand Down

0 comments on commit a4a9840

Please sign in to comment.