Vue provide/inject使用

想象一個場景,子組件依賴父組件傳遞的props,如果有多個這樣的props,其實已經(jīng)很煩了,當有多個子組件,或者孫組件也依賴于由上至下的props時,寫那么多props簡直是要了親命了。

為了解決這種麻煩,產生了vuex。但是我們肯定希望組件的高可復用性,不引入vuex就能實現(xiàn)功能,那就要考慮vue本身是否支持這種能力了。熟悉React開發(fā)的人應該會想到Context這個高階組件,它通過ProviderConsumer,可以使得無限嵌套的父子組件共有一個數(shù)據(jù)源。Vue也有一個類似的,連名字都很相似,就是這篇文章的主人公provideinject。

依賴注入 ,官網(wǎng)有個例子,講述了為何我們需要 provide,它是可以終結復雜數(shù)據(jù)嵌套的神器。慣例先吹一波,不然寫這篇文章的意義沒了,=^^= 。閑話少說,上代碼。

// parent組件
<template>
  <div>
    <div>{{test}}</div>
    <button @click="changeTest">修改test的值</button>
    <son></son>
  </div>
</template>

<script>
import Son from "./Son";
export default {
  name: "parent",
  components: { Son },
  provide() {
    return {
      injectData: this.test
    };
  },
  data() {
    return {
      test: "測試",
    };
  },
  methods: {
    changeTest() {
      this.test = "測試后";
    }
  }
};
</script>

//son組件
<template>
  <div>{{injectData}}</div>
</template>


<script>
export default {
  name: "son",
  inject: ["injectData"],
  mounted() {
    // eslint-disable-next-line
    console.log(this.injectData)
  },
};
</script>

parent組件使用provide提供一個injectData,son組件通過inject獲取到parent注入的數(shù)據(jù),以上就是它的最簡用法。有一點需要注意,我們可以將inject得到的數(shù)據(jù)直接賦值給子組件的dataprops,但是這個是在vue版本2.1之后才有的功能,這版本之前,會在data,props得到之后再得到注入的值。

使用provide/inject我們需要注意的是:

provide/inject這對選項需要一起使用,以允許一個祖先組件向其所有子孫后代注入一個依賴,不論組件層次有多深,并在起上下游關系成立的時間里始終生效。
provide 選項應該是:一個對象或返回一個對象的函數(shù)
inject 選項應該是:一個字符串數(shù)組,或 一個對象,對象的 key 是本地的綁定名

如果我們parent組件里provide是如下代碼:

provide: {
    injectData: this.test
}

我們會發(fā)現(xiàn)this.test所得到的永遠是undefined

 provide: {
      injectData:() => {
        //eslint-disable-next-line
        console.log(this)
      }
  },

我們打印出來的this永遠是undefined,所以我們最好切記使用return返回一個對象,直接賦值對象僅在我們需要傳遞的是靜態(tài)數(shù)據(jù)時再使用。

最開始的例子測試中,我們會得到,provide傳遞的test數(shù)據(jù)并不是響應式的,當parent改變了test的值后,son組件無法得到改變后的值,這就產生了一個問題,我們肯定是希望父子組件拿到的數(shù)據(jù)是相同的。

image.png

我們先看看官網(wǎng)是如何說的,哦,并不直接是可響應的,而是要我們人為使它是可響應的,之前的測試是符合的,因為我們provide的只是一個字符串,可響應的我們很快想到對象數(shù)組這些。這樣又產生一個問題,是provide傳遞的值就必須是個對象,還是說,傳遞的可以是個指針,指向的是個對象呢?實踐出真知,測試一下。

provide() {
    return {
      injectData: this.test
    };
  },
  data() {
    return {
      test: {
        test: "測試"
      },
    };
  },

我們先將provide的改成上面的,結果是響應式的,我們再測試一下另外一種。

provide() {
    return {
      injectData: {
        test: this.test
      }
    };
  },
  data() {
    return {
      test: "測試"
    };
  },

測試得出結果,上面的不是響應式的。事實證明,必須是inject能拿到的數(shù)據(jù)對象響應式,我們才能得到響應式結果。

其實這樣也蠻麻煩的,比如如果父組件有超多需要傳遞下去的數(shù)據(jù),還有個超簡潔的處理方式。

provide() {
  return {
      injectData: this
  }
}

我們可以將父組件整個傳遞到所需組件中去,并且組件實例本身就是響應式的,這樣足以滿足我們大部分組件需求。

使用時,我這邊還是遇到了一種場景,不是provide的問題,但是與之有點關系。當我們將組件實例注入之后,子組件是能拿到組件的所有數(shù)據(jù)的,但是當父組件內里數(shù)據(jù)改變時,子組件是監(jiān)聽不到數(shù)據(jù)的變化的,頁面也無法刷新,我是取了個巧,對數(shù)組進行 splice或者concat等其他會觸發(fā)數(shù)組更新監(jiān)聽的操作,對象的話可以使用...Object.assign。$set沒什么用 ==!響應式更新機制,還是有很多不便的地方,刷新的解決方式還有待商榷,希望有更好的方法。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容