专栏名称: 程序员大咖
程序员大咖,努力成就期待着的自己。分享程序员技术文章、程序员工具资源、程序员精选课程、程序员视频教程、程序员热点资讯、程序员学习资料等。
目录
相关文章推荐
新疆949交通广播  ·  女子得了流感 硬扛3天变“白肺”! ·  昨天  
人民日报评论  ·  找准发力点,干出好年景 | 今日谈 ·  昨天  
求是网  ·  发展动力潜力不断激活 ·  昨天  
CHINADAILY  ·  Editorial丨Youths' ... ·  3 天前  
后沙月光  ·  英国朋友谈哪吒登顶! ·  4 天前  
51好读  ›  专栏  ›  程序员大咖

VueUse 是怎么封装Vue3 Provide/Inject 的?

程序员大咖  · 公众号  ·  · 2025-02-06 10:24

正文

前言


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 }

<script setup lang="ts">
  import { useProvideCounterStore } from './useCounterStore'

  useProvideCounterStore(0)
script>

<template>
  <div>
    <slot />
  div>
template>

<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) => ReturnuseInjectedState: () => Return | undefined
{
  const key: string | InjectionKey = 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);

如果用对象解构,代码会是

typescript
复制代码
const {state:count,setState:setCount} =useState(0)
const {state:double, setState:setDouble} = useState(0);

相比之下数组显得代码更加简洁。

数组解构也有缺点:返回值必须按顺序取值。返回值中只取其中一个,代码就很奇怪。

const






请到「今天看啥」查看全文