专栏名称: 程序员大咖
程序员大咖,努力成就期待着的自己。分享程序员技术文章、程序员工具资源、程序员精选课程、程序员视频教程、程序员热点资讯、程序员学习资料等。
目录
相关文章推荐
新加坡眼  ·  寺庙祈福、吃汤圆...新加坡的元宵节仪式感满满 ·  20 小时前  
生态梦网  ·  网友为滨海这个区域的发展操碎了心... ·  昨天  
51好读  ›  专栏  ›  程序员大咖

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

程序员大咖  · 公众号  ·  · 2024-11-09 10:24

主要观点总结

文章介绍了Provide和Inject在Vue.js中解决Prop逐级透传问题的方法,并指出了其缺点。文章还介绍了VueUse的createInjectionState函数,该函数可以创建可注入组件的全局状态。文章通过示例代码演示了如何使用createInjectionState,并解释了为什么返回的是一个数组。此外,文章还讨论了数组解构和对象解构的区别,并指出在特定情境下使用哪种方式更为合适。最后,文章讨论了提供类似vuex的结构来追踪状态的原因,以及为什么使用readonly修饰符的重要性。

关键观点总结

关键观点1: Provide和Inject可以解决Prop逐级透传问题,但存在无法追踪数据来源和状态变更失控的缺点。

Provide和Inject是Vue.js中用于数据传递的机制,但它们在解决Prop逐级透传问题的同时,也存在无法追踪数据来源的问题。任意层级都可以访问数据,导致数据追踪变得困难。此外,provide/inject容易导致状态变更失控。

关键观点2: VueUse的createInjectionState函数可以创建全局状态,并解决了Provide的问题。

createInjectionState函数通过创建全局状态,解决了Provide无法追踪数据和状态变更的问题。它可以创建可注入组件的全局状态,并提供了方便的API来管理和访问这些状态。

关键观点3: 数组解构和对象解构的区别及使用场景。

数组解构适用于调用多个方法并需要按顺序取值的情况,而对象解构适用于只使用部分返回值且只需要调用一次方法的情况。在createInjectionState的上下文中,由于可能多次调用并返回两个值(useProvidingState和useInjectedState),因此采用数组解构的方式更为合适。

关键观点4: 采用类似vuex的结构能更好地追踪状态。

通过将provide中的对象分为state、getters、actions等部分,并采用类似vuex的结构,可以更好地追踪状态。这种结构有助于解决provide/inject机制中数据追踪困难的问题。

关键观点5: 使用readonly修饰符可以防止状态变更失控。

虽然provide/inject机制容易导致状态变更失控,但通过使useInjectedState返回的状态为只读(readonly),可以更好地防止状态变更失控。这样可以确保在注入的状态中进行的更改不会意外地影响其他部分的应用程序。


正文

前言


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






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