Vue 3 學(xué)習(xí)筆記—Provide 和 Inject 用法及原理
在父子組件傳遞數(shù)據(jù)時(shí),通常使用的是 props 和 emit,父?jìng)髯訒r(shí),使用的是 props,如果是父組件傳孫組件時(shí),就需要先傳給子組件,子組件再傳給孫組件,如果多個(gè)子組件或多個(gè)孫組件使用時(shí),就需要傳很多次,會(huì)很麻煩。
像這種情況,可以使用 provide 和 inject 解決這種問題,不論組件嵌套多深,父組件都可以為所有子組件或?qū)O組件提供數(shù)據(jù),父組件使用 provide 提供數(shù)據(jù),子組件或?qū)O組件 inject 注入數(shù)據(jù)。同時(shí)兄弟組件之間傳值更方便。
一、Vue2 的 provide / inject 使用
provide :是一個(gè)對(duì)象,里面是屬性和值。如:
- provide:{
- info:"值"
- }
如果 provide 需要使用 data 內(nèi)的數(shù)據(jù)時(shí),這樣寫就會(huì)報(bào)錯(cuò)。訪問組件實(shí)例 property 時(shí),需要將 provide 轉(zhuǎn)換為返回對(duì)象的函數(shù)。
- provide(){
- return{
- info: this.msg
- }
- }
inject :是一個(gè)字符串?dāng)?shù)組。如:
- inject: [ 'info' ]
接收上邊 provide 提供的 info 數(shù)據(jù),也可以是一個(gè)對(duì)象,該對(duì)象包含 from 和 default 屬性,from 是可用做的注入內(nèi)容中搜索用的 key,default 屬性是指定默認(rèn)值。
在 vue2 中 project / inject 應(yīng)用:
- //父組件
- export default{
- provide:{
- info:"提供數(shù)據(jù)"
- }
- }
- //子組件
- export default{
- inject:['info'],
- mounted(){
- console.log("接收數(shù)據(jù):", this.info) // 接收數(shù)據(jù):提供數(shù)據(jù)
- }
- }
provide / inject 類似于消息的訂閱和發(fā)布。provide 提供或發(fā)送數(shù)據(jù), inject 接收數(shù)據(jù)。
二、Vue3 的 provide / inject 使用
在組合式 API 中使用 provide/inject,兩個(gè)只能在 setup 期間調(diào)用,使用之前,必須從 vue 顯示導(dǎo)入 provide/inject 方法。
provide 函數(shù)接收兩個(gè)參數(shù):
provide( name,value )
name:定義提供 property 的 name 。
value :property 的值。
使用時(shí):
- import { provide } from "vue"
- export default {
- setup(){
- provide('info',"值")
- }
- }
inject 函數(shù)有兩個(gè)參數(shù):
inject(name,default)
name:接收 provide 提供的屬性名。
default:設(shè)置默認(rèn)值,可以不寫,是可選參數(shù)。
使用時(shí):
- import { inject } from "vue"
- export default {
- setup(){
- inject('info',"設(shè)置默認(rèn)值")
- }
- }
完整實(shí)例1:provide/inject實(shí)例
- //父組件代碼
- <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>
三、添加響應(yīng)性
為了給 provide/inject 添加響應(yīng)性,使用 ref 或 reactive 。
完整實(shí)例2:provide/inject 響應(yīng)式
- //父組件代碼
- <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("今天你學(xué)習(xí)了嗎?")
- setTimeout(()=>{
- info.value = "不找借口,立馬學(xué)習(xí)"
- },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>
上述示例,在父組件或子組件都會(huì)修改 info 的值。
provide / inject 類似于消息的訂閱和發(fā)布,遵循 vue 當(dāng)中的單項(xiàng)數(shù)據(jù)流,什么意思呢?就是數(shù)據(jù)在哪,修改只能在哪,不能在數(shù)據(jù)傳遞處修改數(shù)據(jù),容易造成狀態(tài)不可預(yù)測(cè)。
在訂閱組件內(nèi)修改值的時(shí)候,可以被正常修改,如果其他組件也使用該值的時(shí)候,狀態(tài)容易造成混亂,所以需要在源頭上規(guī)避問題。
readonly 只讀函數(shù),使用之前需要引入,如果給變量加上 readonly 屬性,則該數(shù)據(jù)只能讀取,無法改變,被修改時(shí)會(huì)發(fā)出警告,但不會(huì)改變值。
使用方法:
- import { readonly } from "vue"
- let info = readonly('只讀info值')
- setTimout(()=>{
- info="更新info" //兩秒后更新info的值
- },2000)
運(yùn)行兩秒后,瀏覽器發(fā)出警告,提示 info 值不可修改。
所以我們就給provide發(fā)射出去的數(shù)據(jù),添加一個(gè)只讀屬性,避免發(fā)射出去的數(shù)據(jù)被修改。
完整實(shí)例2的 provide 處添加 readonly 。
- provide('info', readonly(info))
在子組件修改值的時(shí)候,會(huì)有一個(gè)只讀提醒。
修改值的時(shí)候,還是需要在 provide 發(fā)布數(shù)據(jù)的組件內(nèi)修改數(shù)據(jù),所以會(huì)在組件內(nèi)添加修改方法,同時(shí)也發(fā)布出去,在子組件處調(diào)用就可以了。如:
- //發(fā)布
- let info = ref("今天你學(xué)習(xí)了嗎?")
- const changeInfo = (val)=>{
- info.value = val
- }
- provide('info',readonly(info))
- provide('changeInfo',changeInfo)
- //訂閱
- const chang = inject('changeInfo')
- chang('沖向前端工程師')
完整示例3:修改數(shù)據(jù)
- // 父組件代碼
- <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("今天你學(xué)習(xí)了嗎?")
- 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>