Provide/Inject
Provide 和 Inject 能解决 Prop 逐步透传难题。引入值类型不容易使引入维持响应性,但引入一个响应式网站目标,依旧有响应式网站效果。
Provide 的问题就是没法跟踪数据信息的源头,在随意等级都可以浏览造成数据追踪很困难,不清楚是哪一个等级申明了这些或是不清楚哪一层级或多个等级采用了。
看一下 VueUse 的 createInjectionState 是怎么封装 Provide 的,而且如何避免 Provide 问题。
详细介绍
createInjectionState:建立能够引入元件的全局状态。
//useCounterStore.ts
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 }
})
export { useProvideCounterStore }
// If you want to hide `useCounterStore` and wrap it in default value logic or throw error logic, please don't export `useCounterStore`
export { useCounterStore }
<!-- RootComponent.vue -->
<script setup lang="ts">
import { useProvideCounterStore } from './useCounterStore'
useProvideCounterStore(0)
</script>
<template>
<div>
<slot />
</div>
</template>
<!-- CountComponent.vue -->
<script setup lang="ts">
import { useCounterStore } from './useCounterStore'
// use non-null assertion operator to ignore the case that store is not provided.
const { count, double } = useCounterStore()!
// if you want to allow component to working without providing store, you can use follow code instead:
// const { count, double } = useCounterStore() ?? { count: ref(0), double: ref(0) }
// also, you can use another hook to provide default value
// const { count, double } = useCounterStoreWithDefaultValue()
// or throw error
// const { count, double } = useCounterStoreOrThrow()
</script>
<template>
<ul>
<li>
count: {{ count }}
</li>
<li>
double: {{ double }}
</li>
</ul>
</template>
源代码
/**
* Create global state that can be injected into components.
*
* @see https://vueuse.org/createInjectionState
*
*/
export function createInjectionState<Arguments extends Array<any>, Return>(
composable: (...args: Arguments) => Return,
): readonly [useProvidingState: (...args: Arguments) => Return, useInjectedState: () => Return | undefined] {
const key: string | InjectionKey<Return> = Symbol('InjectionState')
const useProvidingState = (...args: Arguments) => {
const state = composable(...args)
provide(key, state)
return state
}
const useInjectedState = () => inject(key)
return [useProvidingState, useInjectedState]
}
思索
为何返回是二维数组
/**
* Create global state that can be injected into components.
*
* @see https://vueuse.org/createInjectionState
*
*/
export function createInjectionState<Arguments extends Array<any>, Return>(
composable: (...args: Arguments) => Return,
): readonly [useProvidingState: (...args: Arguments) => Return, useInjectedState: () => Return | undefined] {
const key: string | InjectionKey<Return> = Symbol('InjectionState')
const useProvidingState = (...args: Arguments) => {
const state = composable(...args)
provide(key, state)
return state
}
const useInjectedState = () => inject(key)
return [useProvidingState, useInjectedState]
}
为何返回是二维数组
createInjectionState 返回二维数组,应用 demo 中使用的二维数组结构的形式。那样二维数组结构跟对象结构有什么不同么?
提及二维数组结构首先想到的就是 react 的 useState。
const [count,setCount] =useState(0)
往往用二维数组结构这是因为在启用好几个 useState 时,便捷取名自变量。
const [count,setCount] =useState(0)
const [double, setDouble] = useState(0);
如果使用目标结构,编码将会是
const {state:count,setState:setCount} =useState(0)
const {state:double, setState:setDouble} = useState(0);
比较之下二维数组看起来编码更为简约。
二维数组结构也是有缺陷:传参务必按序选值。传参上只取其中一个,编码就怪异。
const [,setCount] =useState(0)
因而二维数组结构时适宜应用全部传参,而且数次调用方法的现象;目标结构适宜只用其中不少传参,而且一次调用方法的现象。
createInjectionState 建立的引入情况 key 是 Symbol('InjectionState'),其实就是每一次运转的 key 都不一样,有可能会数次启用 createInjectionState,因而 createInjectionState 选用二维数组结构的形式。但是使用传参很有可能只用 useInjectedState,凡是在 useCounterStore.ts 中又把 useProvideCounterStore 和 useInjectedState 以对象方法导出来防止出现下边怪异的书写。
const [,useCounterStore] =useCounterStore()
应用事例里的 state 构造
应用实例里将 provide 里的目标分成 state、getters、actions。构造特想 vuex,而 useProvideCounterStore 等同于 vuex 里的 mutation。选用这样的设计是由于 provide 的缺陷:没法跟踪数据信息的源头,在随意等级都可以浏览造成数据追踪很困难,不清楚是哪一个等级申明了这些或是不清楚哪一层级或多个等级采用了。
选用相近 vuex 的构造能相对性好一点的跟踪情况。
// state
const count = ref(initialValue)
// getters
const double = computed(() => count.value * 2)
// actions
function increment() {
count.value
}
readonly
createInjectionState 返回二维数组是 readonly 修饰的,useInjectedState 返回目标并没用 readonly 装饰,provide/inject 的缺点是情况目标不太好追踪,容易造成情况变动无法控制。即然带来了 useProvidingState 修改状态的办法,useInjectedState 返回情况假如是写保护的可以更好地避免情况变动无法控制。
本站是一个以CSS、JavaScript、Vue、HTML为中心的前端开发技术网址。我们的使命是为众多前端工程师者提供全方位、全方位、好用的前端工程师专业知识和技术服务。 在网站上,大家可以学到最新前端开发技术,掌握前端工程师最新发布的趋势和良好实践。大家提供大量实例教程和实例,让大家可以快速上手前端工程师的关键技术和程序。 本站还提供了一系列好用的工具软件,帮助你更高效地开展前端工程师工作中。公司提供的一种手段和软件都要经过精心策划和改进,能够帮助你节约时间精力,提高研发效率。 此外,本站还拥有一个有活力的小区,你可以在社区里与其它前端工程师者沟通交流技术性、交流经验、处理问题。我们坚信,街道的能量能够帮助你能够更好地进步与成长。 在网站上,大家可以寻找你需要的一切前端工程师网络资源,使您成为一名更加出色的网页开发者。欢迎你添加我们的大家庭,一起探索前端工程师的无限潜能!