首页 > 其他分享 >VueUse 是怎么封装Vue3 Provide/Inject 的?

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

时间:2023-05-07 14:55:52浏览次数:46  
标签:count const VueUse Provide double 解构 state useCounterStore Inject

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]
}

思考

为什么返回的是数组

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 返回的状态如果是只读的能更好防止状态变更失控。

标签:count,const,VueUse,Provide,double,解构,state,useCounterStore,Inject
From: https://www.cnblogs.com/hetaojs/p/17379325.html

相关文章

  • 一统天下 flutter - 存储: path_provider - 用于获取不同平台的本地存储的路径
    源码https://github.com/webabcd/flutter_demo作者webabcd一统天下flutter-存储:path_provider-用于获取不同平台的本地存储的路径示例如下:lib\storage\path_provider.dart/**path_provider-用于获取不同平台的本地存储的路径**在pubspec.yaml中做如......
  • java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/
    Java使用AES/CBC/PKCS7Padding加解密时会报错,因为原生JDK不支持。1.在jdk中的jre\lib\security修改java.security文件,替换security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider2./jdk/jre/lib/ext下添加jar包bcprov-jdk15on-1.58.jar ......
  • 无法将“Autodesk.autocad.livepreview.previewruleprovider”的对象强制转换为类型“
    具体问题如下图所示:在vs2010中调试中,会调用CAD2014,这时就会出现上述的问题错误;经查找,具体的问题是因为:cad的dll引用中,“复制本地”设置为True,因更改为false;这里要注意的是,每个项目中的引用都要更改为false,如Hello项目和InitAndOpt项目中的引用,都要为false,否则这个错误一直会出......
  • 坑系列 (Angular 2+ ) -> 控制反转C(Inversion of Control)和 依赖注入DI(Dependency
        控制反转IOC和依赖注入DI这两个概念其实有太多优秀的文章,由浅入深,从不同的角度,再到不同的比喻进行了讲解,对于新手的我来说,看完之后,好像看了又没完全看,回头摸索实践,还是总有种似懂非懂,懂了又没完全懂(‘X了又没完全XXX’句式是2021年某个梗嘻嘻......
  • Sql Server 2005 在建立与服务器的连接时出错。provider,error: 40
    在建立与服务器的连接时出错。在连接到SQLServer2005时,在默认的设置下SQLServer不允许进行远程连接可能会导致此失败。(provider:命名管道提供程序,error:40-无法打开到SQLServer的连接)(.NetSqlClientDataProvider) 网上找的解决办法对我的不适用下面上网......
  • Langchain框架 prompt injection注入
    Langchain框架promptinjection注入PromptInjection是一种攻击技术,黑客或恶意攻击者操纵AI模型的输入值,以诱导模型返回非预期的结果Langchain框架LangChain是一个基于大语言模型进行应用开发的框架。所谓大语言模型(LargeLanguageModels,LLMs),是指基于海量语料训练、......
  • Linux common clock framework(2)_clock provider
    1.前言本文接上篇文章,从clockdriver的角度,分析怎么借助commonclockframework管理系统的时钟资源。换句话说,就是怎么编写一个clockdriver。由于kernel称clockdriver为clockprovider(相应的,clock的使用者为clockconsumer),因此本文遵循这个规则,统一以clockprovider命名。2.......
  • Oracle sql injection
    先创建一个普通用户并授权:C:\>sqlplus"/assysdba"SQL*Plus:Release10.2.0.1.0-Productionon星期三7月3121:49:452013Copyright(c)1982,2005,Oracle.Allrightsreserved.连接到:PersonalOracleDatabase10gRelease10.2.0.1.0-ProductionWiththe......
  • SQL Injector - POST Parameter Attack
    login.jsp如下:<%@pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPEhtmlPUBLIC"-//W3C//DTDHTML4.01Transitional//EN""http://www.w3.org/TR/html4/loose.d......
  • SQL Injector - GET Manual Setup Binary Payload Attack
    bt5上操作:***********************************************************************Fast-Track-Anewbeginning...****Version:4.0.2......