VueUse 是怎么封装Vue3 Provide/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 返回的状态如果是只读的能更好防止状态变更失控。
VueUse 是怎么封装Vue3 Provide/Inject 的?的更多相关文章
- 小项目中vuex使用频率不太多我们完全可以用provide inject 来代替可以让项目小不少
在一般小型项目中vuex实在是太浪费了所以我们可以用到 vue中的provide inject 代替 1.在vue3中我们先另起一个 文件创建一个全局的状态和方法的地方(如果你的全局状态特别的多记得要 ...
- vue高级组件之provide / inject
转载:https://blog.csdn.net/Garrettzxd/article/details/81407199 在vue中不同组件通信方式如下 1.父子组件,通过prop 2.非父子组件,通 ...
- vue中的provide/inject的学习
在 Vue.js 的 2.2.0+ 版本中添加加了 provide 和 inject 选项.用于父级组件向下传递数据.provide/inject:简单的来说就是在父组件(或者曾祖父组件)中通过pro ...
- vue 初步了解provide/inject
provider/inject:简单的来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量. 需要注意的是 provide / inject这对选项需要一起使用, ...
- Vue provide/inject 部分源码分析 实现响应式数据更新
provide/inject 数据响应式更新的坑及源码解析 下面是我自己曾经遇到 一个问题,直接以自己QA的形式来写吧 自问自答了,需要的同学也可以直接访问segmentfault地址 官网给出实例, ...
- 组件的通信 :provide / inject 对象进入后,就等于不用props,然后内部对象,直接复制可以接受数组,属性不能直接复制,可以用Object.assgin覆盖对象,或者Vue的set 双向绑定数据
组件的通信 :provide / inject 对象进入后,就等于不用props,然后内部对象,直接复制可以接受数组,属性不能直接复制,可以用Object.assgin覆盖对象,或者Vue的set 双 ...
- Vue实战指南之依赖注入(provide / inject)
案例 UI美眉说咱家的选项菜单太丑了,小哥哥能不能美化一下呀,洒家自然是说小意思啦~自定义一个select组件,so easy~ 简单粗暴型: <el-select v-model=" ...
- 在vue中使用[provide/inject]实现页面reload
在vue中实现页面刷新有不同的方法: 如:this.$router.go(0),location.reload()等,但是或多或少会存在问题,如页面会一闪等 所以建议使用[provide/inject ...
- 聊聊 Vue 中 provide/inject 的应用
众所周知,在组件式开发中,最大的痛点就在于组件之间的通信.在 Vue 中,Vue 提供了各种各样的组件通信方式,从基础的 props/$emit 到用于兄弟组件通信的 EventBus,再到用于全局数 ...
- Vue.js 源码分析(八) 基础篇 依赖注入 provide/inject组合详解
先来看看官网的介绍: 简单的说,当组件的引入层次过多,我们的子孙组件想要获取祖先组件的资源,那么怎么办呢,总不能一直取父级往上吧,而且这样代码结构容易混乱.这个就是这对选项要干的事情 provide和 ...
随机推荐
- CH573 CH579 CH582程序烧录讲解
WCH的蓝牙芯片CH57x/CH58x系类大部分是支持串口烧录.USB烧录和LINK烧录的,除了一些特殊的封装,如571K,它引脚较少,只支持串口免按键烧录. 仿真下载:ARM内核的CH579支持Jl ...
- SAN证书(转载)
日常在周末更新相关容器,更新 potainer 2.6.3 后发现所有远程 docker 节点都无法连接了,看了下日志报错是这样的: background schedule error (endpoi ...
- 二、pycharm的安装
1.python安装教程在上一篇已描述,详情查看: 2.安装pycharm 首先从网站下载pycharm:链接为:http://www.jetbrains.com/pycharm/download/# ...
- FastReport OpenSource发布到Linux上的准备
一.安装libgdiplus(libgdiplus是一个Mono库,用于对非Windows操作系统提供GDI+兼容的API) apt-get install build-essential lib ...
- Android进度表示
在连接上数据库之后,一切都变得简单了呢! 开心,很轻松地就能够将APP里面的相关内容写完啦! 尝试了好久的连接Mysql数据库,最后还是没有成功: 虽然Android studio里面自带的SQLit ...
- Javaweb基础复习------Cookie+Session案例的实现(登录注册案例)
Cookie对象的创建--Cookie cookie=new Cookie("key","value"); 发送Cookie:resp.addCookie(); ...
- Javaweb基础复习------EL表达式+JSTL-if&foreach
EL表达式------简化JSP页面的Java代码 主要功能是------获取数据(语法:${data}) 举例: //ServletDemo1.java package com.example.se ...
- flex弹性盒子中flex-grow与flex的区别
大家在使用flex布局的时候很多情况下都会用到flex-grow这个属性, flex-grow 属性用于设置父元素剩余空间的瓜分比例, flex 属性是 flex-grow.flex-shrink ...
- cookie时效无限延长方案
作者:京东科技 刘清洁 1.痛点(*) 自动化测试有2种形式,接口自动化和UI自动化.而UI自动化经常会被登录节点堵塞,例如验证码.图形.滑块等,尽管有些方式可以识别图形和定位滑块位置,但成功率都不高 ...
- ES(ECMAScript)标准下中的let、var和const
ES标准下中的let,var和const let会报重复声明,var则比较随意,重不重复无所谓 // 使用 var 的时候重复声明变量是没问题的,只不过就是后面会把前面覆盖掉 var num = 10 ...