vue中组合式 API-依赖注入之provide和inject的用法(二)——添加响应性 & 污染全局数据、破坏了单向数据流,vuex可追踪数据 & 三种通信方式之父子通信、兄弟通信、跨级通信

vue中组合式 API-依赖注入之provide和inject的用法(二)——添加响应性 & 污染全局数据、破坏了单向数据流,vuex可追踪数据 & 三种通信方式之父子通信、兄弟通信、跨级通信

1、给 provide/inject 添加响应性

在vue3中给 provide/inject 添加响应性,使用 ref 或 reactive 。

//父组件代码
<template>
  <div>
    info:{{info}}
    <InjectCom ></InjectCom>
  </div>
</template>
<script>
import InjectCom from "./InjectCom"
import { provide,readonly,ref } from "vue"
export default {
  setup(){
    let info = ref("今天你学习了吗?")
    setTimeout(()=>{
      info.value = "不找借口,立马学习"
    },2000)
    provide('info',info)
    return{
      info
    }
  },
  components:{
    InjectCom
  }
}
</script>

// InjectCom 子/孙组件代码
<template>
 {{info}}
</template>
<script>
import { inject } from "vue"
export default {
  setup(){
    const info = inject('info')
    setTimeout(()=>{
      info.value = "更新"
    },2000)
    return{
      info
    }
  }
}
</script>

上述示例,在父组件或子组件都会修改 info 的值。
provide / inject 类似于消息的订阅和发布,遵循 vue 当中的单项数据流,什么意思呢?就是数据在哪,修改只能在哪,不能在数据传递处修改数据,容易造成状态不可预测。

在订阅组件内修改值的时候,可以被正常修改,如果其他组件也使用该值的时候,状态容易造成混乱,所以需要在源头上规避问题。

readonly 只读函数,使用之前需要引入,如果给变量加上 readonly 属性,则该数据只能读取,无法改变,被修改时会发出警告,但不会改变值。

使用方法:

import { readonly } from "vue"
let info = readonly('只读info值')
setTimout(()=>{
 info="更新info" //两秒后更新info的值
},2000)

运行两秒后,浏览器发出警告,提示 info 值不可修改。
所以我们就给provide发射出去的数据,添加一个只读属性,避免发射出去的数据被修改。在上面实例3的 provide 处添加 readonly 。

provide('info', readonly(info))

在子组件修改值的时候,会有一个只读提醒。
所以在修改值的时候,还是需要在 provide 发布数据的组件内修改数据,在父组件内添加修改方法,同时也发布出去,在子组件处调用就可以了。如:

//发布
let info = ref("今天你学习了吗?")
const changeInfo = (val)=>{
 info.value = val
}
provide('info',readonly(info))
provide('changeInfo',changeInfo)

//订阅
const chang = inject('changeInfo')
chang('冲向前端工程师')

完整示例:

// 父组件代码
<template>
  <div>
    info:{{info}}
    <InjectCom ></InjectCom>
  </div>
</template>

<script>
import InjectCom from "./InjectCom"
import { provide,readonly,ref } from "vue"
export default {
  setup(){
    let info = ref("今天你学习了吗?")
    const changeInfo = (val)=>{
      info.value = val
    }
    provide('info',readonly(info))
    provide('changeInfo',changeInfo)
    return{
      info
    }
  },
  components:{
    InjectCom
  }
}
</script>

//InjectCom 子组件代码
<template>
  <div>
    <button @click="chang('冲向前端工程师')">更新值</button>
  </div>
</template>
<script>
import { inject } from "vue"
export default {
  setup(){
    const info = inject('info')
    const chang = inject('changeInfo')
    return{
      info,
      chang
    }
  }
}
</script>
2、慎用 provide / inject

既然 provide/inject 如此好用,那么,为什么 Vue 官方还要推荐我们使用 Vuex,而不是用原生的 API 呢?

前面提到过,Vuex 和 provide/inject 最大的区别

Vuex 中的全局状态的每次修改是可以追踪回溯的,而 provide/inject 中变量的修改是无法控制的。换句话说,不知道是哪个组件修改了这个全局状态。

Vue 的设计理念借鉴了 React 中的单向数据流原则(虽然有 sync 这种破坏单向数据流的家伙),而 provide/inject 明显破坏了单向数据流原则。试想,如果有多个后代组件同时依赖于一个祖先组件提供的状态,那么只要有一个组件修改了该状态,那么所有组件都会受到影响。这一方面增加了耦合度,另一方面,使得数据变化不可控。如果在多人协作开发中,这将成为一个噩梦。

在这里,总结了使用 provide/inject 做全局状态管理的原则:

  • 多人协作时,做好作用域隔离;

  • 尽量使用一次性数据作为全局状态

看起来,使用 provide / inject 做全局状态管理好像很危险,那么有没有 provide / inject 更好的使用方式呢?
当然有,那就是使用 provide / inject 编写组件。

使用 provide / inject 编写组件

使用 provide/inject 做组件开发,是 Vue 官方文档中提倡的一种做法。

以我们比较熟悉的 elementUI 来举例:

在 elementUI 中有 Button(按钮)组件,当在 Form(表单)组件中使用时,它的尺寸会同时受到外层的 FormItem 组件以及更外层的 Form 组件中的 size 属性的影响。

如果是常规方案,我们可以通过 props 从 Form 开始,一层层往下传递属性值。看起来只需要传递传递两层即可,还可以接受。但是,Form 的下一层组件不一定是 FormItem,FormItem 的下一层组件不一定是 Button,它们之间还可以嵌套其他组件,也就是说,层级关系不确定。如果使用 props,我们写的组件会出现强耦合的情况。

provide/inject 可以完美的解决这个问题,只需要向后代注入组件本身(上下文),后代组件中可以无视层级任意访问祖先组件中的状态。

部分源码如下:

export default {
  name: 'ElButton',
  // 通过 inject 获取 elForm 以及 elFormItem 这两个组件
  inject: {
    elForm: {
      default: ''
    },
    elFormItem: {
      default: ''
    }
  },
  // ...
  computed: {
    _elFormItemSize() {
      return (this.elFormItem || {}).elFormItemSize;
    },
    buttonSize() {
      return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
    },
    //...
  },
  // ...
};
3、Vue中常见的组件通信方式可分为三类

1、父子通信

  • 父向子传递数据是通过 props,子向父是通过 events($emit);

  • 通过父链 / 子链也可以通信($parent / $children);

  • ref 也可以访问组件实例;

  • provide / inject;

  • a t t r s / attrs/ attrs/listeners;

2、兄弟通信

  • Bus;
  • Vuex;

3、跨级通信

  • Bus;
  • Vuex;
  • provide / inject
  • $attrs / $listeners
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3组合式API使用vue-baidu-map-3x自定义地图心点,可以按照以下步骤: 1. 安装vue-baidu-map-3x 你可以通过以下命令使用npm安装vue-baidu-map-3x: ``` npm install vue-baidu-map-3x --save ``` 2. 在组合式API引入vue-baidu-map-3x 在需要使用百度地图的组件,你需要先引入vue-baidu-map-3x。例如,在一个名为Map.vue的组件,你可以这样引入: ``` <script> import { defineComponent } from 'vue' import BaiduMap from 'vue-baidu-map-3x' export default defineComponent({ components: { BaiduMap }, setup() { // 组合式API的代码 } }) </script> ``` 3. 在setup函数定义地图心点 在setup函数,你可以定义地图的心点和缩放级别。例如: ``` <script> import { defineComponent } from 'vue' import BaiduMap from 'vue-baidu-map-3x' export default defineComponent({ components: { BaiduMap }, setup() { const center = { lng: 116.404, lat: 39.915 } const zoom = 12 return { center, zoom } } }) </script> ``` 在这个例子,我们定义了地图的心点为北京市心,缩放级别为12。 4. 在模板使用地图 最后,在模板使用vue-baidu-map-3x组件,并且传入定义的心点和缩放级别。例如: ``` <template> <div class="map-container"> <baidu-map :center="center" :zoom="zoom"></baidu-map> </div> </template> ``` 现在,你已经在Vue3组合式API使用vue-baidu-map-3x自定义了地图的心点。你可以通过修改center的值来改变地图的心点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值