vue 3 學習筆記 (八)——provide 和 inject 用法及原理

前端人發表於2021-11-26

在父子元件傳遞資料時,通常使用的是 props 和 emit,父傳子時,使用的是 props,如果是父元件傳孫元件時,就需要先傳給子元件,子元件再傳給孫元件,如果多個子元件或多個孫元件使用時,就需要傳很多次,會很麻煩。

像這種情況,可以使用 provide 和 inject 解決這種問題,不論元件巢狀多深,父元件都可以為所有子元件或孫元件提供資料,父元件使用 provide 提供資料,子元件或孫元件 inject 注入資料。同時兄弟元件之間傳值更方便。

一、Vue2 的 provide / inject 使用

provide :是一個物件,裡面是屬性和值。如:

provide:{
 info:"值"
}

 

如果 provide 需要使用 data 內的資料時,這樣寫就會報錯。訪問元件例項 property 時,需要將 provide 轉換為返回物件的函式。

provide(){
 return{
  info: this.msg
 }
}

 

inject :是一個字串陣列。如:

inject: [ 'info' ]

 

接收上邊 provide 提供的 info 資料,也可以是一個物件,該物件包含 from 和 default 屬性,from 是可用做的注入內容中搜尋用的 key,default 屬性是指定預設值。

在 vue2 中 project / inject 應用:

//父元件
export default{
 provide:{
  info:"提供資料"
 }
}
//子元件
export default{
 inject:['info'],
 mounted(){
     console.log("接收資料:", this.info) // 接收資料:提供資料
 }
} 

 

provide / inject 類似於訊息的訂閱和釋出。provide 提供或傳送資料, inject 接收資料。

二、Vue3 的 provide / inject 使用

在組合式 API 中使用 provide/inject,兩個只能在 setup 期間呼叫,使用之前,必須從 vue 顯示匯入 provide/inject 方法。

provide 函式接收兩個引數:

provide( name,value )

name:定義提供 property 的 name 。

value :property 的值。

使用時:

import { provide } from "vue"
export default {
  setup(){
    provide('info',"值")
  }
}

 

inject 函式有兩個引數:

inject(name,default)

name:接收 provide 提供的屬性名。

default:設定預設值,可以不寫,是可選引數。

使用時:

import { inject } from "vue"
export default {
  setup(){
    inject('info',"設定預設值")
  }
}

 

完整例項1:provide/inject例項

//父元件程式碼
<script>
import { provide } from "vue"
export default {
  setup(){
    provide('info',"值")
  }
}
</script>

//子元件 程式碼
<template>
 {{info}}
</template>
<script>
import { inject } from "vue"
export default {
  setup(){
    const info = inject('info')
    return{
      info
    }
  }
}
</script>

 

三、新增響應性

為了給 provide/inject 新增響應性,使用 ref 或 reactive 。

完整例項2:provide/inject 響應式

//父元件程式碼
<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發射出去的資料,新增一個只讀屬性,避免發射出去的資料被修改。

完整例項2的 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('衝向前端工程師')

 

完整示例3:修改資料

// 父元件程式碼
<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>

 

相關文章