Skip to content

Commit

Permalink
feat(createInjectionState): add injectionKey option (#3404)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
PPetau and antfu committed Oct 7, 2023
1 parent c3a69ee commit 90d3400
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 32 deletions.
27 changes: 27 additions & 0 deletions packages/shared/createInjectionState/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,30 @@ const { increment } = useCounterStore()!
</button>
</template>
```

## Provide a custom InjectionKey


```ts
// useCounterStore.ts
import { computed, ref } from 'vue'
import { createInjectionState } from '@vueuse/shared'

// custom injectionKey
const CounterStoreKey = 'counter-store'

const [useProvideCounterStore, useCounterStore] = createInjectionState((initialValue: number) => {
// state
const count = ref(initialValue)

// getters
const double = computed(() => count.value * 2)

// actions
function increment() {
count.value++
}

return { count, double, increment }
}, { injectionKey: CounterStoreKey })
```
95 changes: 64 additions & 31 deletions packages/shared/createInjectionState/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,81 @@
import { defineComponent, h, ref } from 'vue-demi'
import { type InjectionKey, type Ref, defineComponent, h, inject, ref } from 'vue-demi'
import { createInjectionState } from '@vueuse/shared'
import { describe, expect, it } from 'vitest'
import { mount } from '../../.test'

const [useProvideCountState, useCountState] = createInjectionState((initialValue: number) => {
const count = ref(initialValue)
return count
})
describe('createInjectionState', () => {
it('should work 1', () => {
const [useProvideCountState, useCountState] = createInjectionState((initialValue: number) => {
const count = ref(initialValue)
return count
})

const ChildComponent = defineComponent({
setup() {
const count = useCountState()
expect(count?.value).toBe(0)
const ChildComponent = defineComponent({
setup() {
const count = useCountState()
expect(count?.value).toBe(0)

return () => h('div')
},
})
return () => h('div')
},
})

const RootComponent = defineComponent({
setup() {
useProvideCountState(0)
const RootComponent = defineComponent({
setup() {
useProvideCountState(0)

return () => h(ChildComponent)
},
})
return () => h(ChildComponent)
},
})

describe('createInjectionState simple example', () => {
it('should work', () => {
mount(RootComponent)
})
})

const CanProvidingStateAndInjectedStateInSameComponent = defineComponent({
setup() {
useProvideCountState(114514)
const count = useCountState()!
expect(count.value).toBe(114514)
it('should work (custom key)', () => {
const KEY: InjectionKey<Ref<number>> = Symbol('count-state')

return () => h('div')
},
})
const [useProvideCountState, useCountState] = createInjectionState((initialValue: number) => {
const count = ref(initialValue)
return count
}, { injectionKey: KEY })

const ChildComponent = defineComponent({
setup() {
const count = useCountState()
expect(count?.value).toBe(0)
const count2 = inject(KEY)
expect(count2?.value).toBe(0)

return () => h('div')
},
})

const RootComponent = defineComponent({
setup() {
useProvideCountState(0)

return () => h(ChildComponent)
},
})

mount(RootComponent)
})

it('allow call provideLocal and injectLocal in same component', () => {
const [useProvideCountState, useCountState] = createInjectionState((initialValue: number) => {
const count = ref(initialValue)
return count
})

const CanProvidingStateAndInjectedStateInSameComponent = defineComponent({
setup() {
useProvideCountState(114514)
const count = useCountState()!
expect(count.value).toBe(114514)

return () => h('div')
},
})

describe('allow call useProvidingState and useInjectedState in same component', () => {
it('should work', () => {
mount(CanProvidingStateAndInjectedStateInSameComponent)
})
})
10 changes: 9 additions & 1 deletion packages/shared/createInjectionState/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ import type { InjectionKey } from 'vue-demi'
import { provideLocal } from '../provideLocal'
import { injectLocal } from '../injectLocal'

export interface CreateInjectionStateOptions<Return> {
/**
* Custom injectionKey for InjectionState
*/
injectionKey?: string | InjectionKey<Return>
}

/**
* Create global state that can be injected into components.
*
Expand All @@ -10,8 +17,9 @@ import { injectLocal } from '../injectLocal'
*/
export function createInjectionState<Arguments extends Array<any>, Return>(
composable: (...args: Arguments) => Return,
options?: CreateInjectionStateOptions<Return>,
): readonly [useProvidingState: (...args: Arguments) => Return, useInjectedState: () => Return | undefined] {
const key: string | InjectionKey<Return> = Symbol('InjectionState')
const key: string | InjectionKey<Return> = options?.injectionKey || Symbol('InjectionState')
const useProvidingState = (...args: Arguments) => {
const state = composable(...args)
provideLocal(key, state)
Expand Down

0 comments on commit 90d3400

Please sign in to comment.