Provide/inject 真的可以取代 Vuex 嗎?

Hello,各位小伙伴,接下來的一段時間里,我會把我的課程《Vue.js 3.0 核心源碼解析》中問題的答案陸續在我的公眾號發布,由于課程的問題大多數都是開放性的問題,所以我的答案也不一定是標準的,僅供你參考喔。

本期的問題:如果你想利用依賴注入讓整個應用下組件都能共享某個數據,你會怎么做?為什么?

這個問題本身并不難,因為你只要知道了依賴注入的實現原理,你就可以輕松回答出:只要在應用的根實例上 provide 某個數據,然后在子組件 inject 使用,就相當于整個應用的組件共享該數據了。

看上去,使用 provide/inject 就可以實現全局數據共享,這個能力似乎和 Vuex 提供的能力類似,那么它可以替代 Vuex 嗎?

Vuex 的核心概念

Vuex 是什么,官方的解釋是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,并以相應的規則保證狀態以一種可預測的方式發生變化。

Vuex 本質上是一種全局單例模式的方式來管理組件的共享狀態。在這種模式下,我們的組件樹構成了一個巨大的“視圖”,不管在樹的哪個位置,任何組件都能獲取狀態或者觸發行為。

Vuex 中,有四個核心的概念,我們來簡單過一下。

  • State

stateVuex 中最基礎的概念,它用于數據的 存儲,舉個例子:

import?{?createStore?}?from?'vuex'
const?store?=?createStore({state:?{todos:?[{?id:?1,?text:?'...',?done:?true?},{?id:?2,?text:?'...',?done:?false?}]}
})

我們可以通過 store.state.todos 來訪問到其中的 todos 數據。

  • Getter

有些時候,我們希望獲取的數據可能不是單一的在 state 中的數據,可能需要做一些邏輯運算,我們可以使用 getter,它就是 store 的計算屬性。延續前一個例子:

import?{?createStore?}?from?'vuex'
const?store?=?createStore({state:?{todos:?[{?id:?1,?text:?'...',?done:?true?},{?id:?2,?text:?'...',?done:?false?}]},getters:?{doneTodos:?state?=>?{return?state.todos.filter(todo?=>?todo.done)}}
})

我們可以通過 store.getters.doneTodos 訪問到所有已完成的 todos 數據。

  • Mutation

數據有讀就會有寫,為了確保數據的改變可追蹤,更改 state 數據的唯一的方式是提交 mutation。延續前一個例子:

import?{?createStore?}?from?'vuex'
const?store?=?createStore({state:?{todos:?[{?id:?1,?text:?'...',?done:?true?},{?id:?2,?text:?'...',?done:?false?}]},getters:?{doneTodos:?state?=>?{return?state.todos.filter(todo?=>?todo.done)}},mutations:?{finishToDo(state,?index)?{state.todos[index].done?=?true}}
})

我們可以通過 store.commit('finishTodo', 1) 來修改第二個 todo 的完成狀態。

  • Action

action 類似 mutation,不同在于在 action 內部并不直接修改數據,還是通過提交 mutation 來更改數據,此外 action 內部還能包含任意的異步操作。延續前一個例子:

import?{?createStore?}?from?'vuex'
const?store?=?createStore({state:?{todos:?[{?id:?1,?text:?'...',?done:?true?},{?id:?2,?text:?'...',?done:?false?}]},getters:?{doneTodos:?state?=>?{return?state.todos.filter(todo?=>?todo.done)}},mutations:?{finishToDo(state,?index)?{state.todos[index].done?=?true}},actions:?{delayFinishTodo({commit},?index)?{setTimeout(()?=>?{commit('finishToDo',?index)},?1000)}}
})

我們可以通過 store.dispatch('delayFinishTodo', 1) 延時 1s 后修改第二個 todo 的完成狀態。

至此,我們了解了 Vuex 的四個最核心的概念,目前為止,我們都是通過原生 JavaScript 去操作 store 實例,并沒有和組件關聯,那么我們如何在組件中訪問到 store 實例呢?

在組件中訪問 store

在 Vue.js 3.0 中,我們通過 createStore 創建了 store 實例后,會在創建 App 對象的時候注入進去。

import?{?createApp?}?from?'vue'
import?App?from?'./App.vue'
import?store?from?'./store'createApp(App).use(store).mount('#app')

當執行 createApp(App).use(store) 的時候,相當于注冊了 store 的插件,會執行到 store 提供的 install 方法,來看看 4.0 版本的 Vuex 是如何實現 install 方法的:

export?class?Store?{install?(app,?injectKey)?{app.provide(injectKey?||?storeKey,?this)app.config.globalProperties.$store?=?this}
}

在注冊插件的時候,內部通過 app.providestore 實例 provide 到了根實例中,此外,store 實例也被添加到了全局屬性的 app.config.globalProperties.$store 中。

這么做之后,我們就可以在組件中輕松訪問到 store 實例了。其中 app.provide 是給 Composition API 方式編寫的組件用的,因為一旦使用了 Composition API ,我們在組件中想訪問 store 的話會在 setup 函數中通過 useStore API 拿到,如下:

import?{?useStore?}?from?'vuex'
export?default?{setup()?{const?store?=?useStore()}
}

useStore 的實現如下:

import?{?inject?}?from?'vue'
export?const?storeKey?=?'store'
export?function?useStore?(key?=?null)?{return?inject(key?!==?null???key?:?storeKey)
}

原來 Vuex 就是利用了 provide/inject 依賴注入的 API 實現了在組件中訪問到 store,由于是通過 app.providestore 實例 provide 到根實例中,所以在 app 內部的任意組件中都可以 inject store 實例并訪問了。

除了 Composition API,Vue.js 3.0 依然支持 Options API 的方式去編寫組件,顯然在 Options API 組件中我們依然可以通過 this.$store 訪問到 store 實例,因為實例的查找最終會找到全局 globalProperties 中的屬性。

所以我們看到 provide/injectVuex 中的作用就是讓組件可以訪問到 store 實例。

Vuex 的其它能力

Vuex 除了管理組件的共享狀態,還有一些其他好用的特性,這里我介紹三個常用的特性。

  • 模塊

由于使用單一狀態樹,應用的所有狀態會集中到一個比較大的對象。當應用變得非常復雜時,store 對象就有可能變得相當臃腫。

為了解決以上問題,Vuex 允許我們將 store 分割成模塊(module)。每個模塊擁有自己的 stategettermutationaction、甚至是嵌套子模塊——從上至下進行同樣方式的分割:

const?moduleA?=?{state:?()?=>?({?...?}),mutations:?{?...?},actions:?{?...?},getters:?{?...?}
}const?moduleB?=?{state:?()?=>?({?...?}),mutations:?{?...?},actions:?{?...?}
}const?store?=?createStore({modules:?{a:?moduleA,b:?moduleB}
})store.state.a?//?->?moduleA?的狀態
store.state.b?//?->?moduleB?的狀態

另外,在 store 創建之后,你可以使用 store.registerModule 方法動態注冊模塊:

import?{?createStore?}?from?'vuex'const?store?=?createStore({?/*?options?*/?})//?注冊模塊?`myModule`
store.registerModule('myModule',?{//?...
})//?注冊嵌套模塊?`nested/myModule`
store.registerModule(['nested',?'myModule'],?{//?...
})
  • 插件

Vuexstore 接受 plugins 選項,這個選項暴露出每次 mutation 的鉤子。Vuex 插件就是一個函數,它接收 store 作為唯一參數:

const?myPlugin?=?(store)?=>?{//?在?store?初始化的時候調用store.subscribe((mutation,?state)?=>?{//?每次提交?mutation?的時候調用})
}

然后像這樣使用:

import?{?createStore?}?from?'vuex'
const?store?=?createStore({//?...plugins:?[myPlugin]
})

官方內置了 Logger 插件用于一般的調試:

import?{?createStore,?createLogger?}?from?'vuex'
const?store?=?createStore({//?...plugins:?[createLogger()]
})

通常我們會在開發環境中使用它,用來輸出提交的 mutation 和生成狀態快照。

  • 嚴格模式

為了保證數據的變化可追蹤,我們要求所有狀態的更改都應該通過提交 mutation 來觸發,因此在嚴格模式下,一旦發生了狀態變更且不是由 mutation 函數引起的,將會拋出錯誤。

我們可以在創建 store 的時候開啟:

const?store?=?createStore({//?...strict:?true
})

由于開啟嚴格模式會有一定的性能損耗,我們也只會在開發環境中開啟它。

總結

綜上,我們發現 Vuex 提供的能力還是很豐富的,而僅僅用 provide/inject 是不能替代 Vuex 的,那么 provide/inject 有哪些應用場景呢?

其實這個在課程中已經說了,我比較推薦在組件庫的開發中使用,因為對于一個特定組件,它和其嵌套的子組件上下文聯系很緊密。

我出這個題主要是希望你能做到以下兩點:

  1. 從源碼層面探索,了解 provide/inject 的實現原理。

  2. 延伸思考 provide/inject 在實現全局數據共享需求與 Vuex 的相同與差異。

要記住,分析和思考的過程遠比答案重要。


你好,我是若川,江西人~(點擊藍字了解我)歷時一年只寫了一個學習源碼整體架構系列?有哪些必看的JS庫:jQuery、underscore、lodash、sentry、vuex、axios、koa、redux

  1. 關注若川視野,回復"pdf" 領取優質前端書籍pdf,回復"1",可加群長期交流學習

  2. 我的博客地址:https://lxchuan12.gitee.io?歡迎收藏

  3. 覺得文章不錯,可以?分享、點贊、在看?呀^_^另外歡迎留言交流~

小提醒:若川視野公眾號面試、源碼等文章合集在菜單欄中間【源碼精選】按鈕,歡迎點擊閱讀,也可以星標我的公眾號,便于查找

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/276185.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/276185.shtml
英文地址,請注明出處:http://en.pswp.cn/news/276185.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

php 計算代碼執行時間

轉載鏈接:http://blog.csdn.net/php_boy/article/details/6450678 class runtime {var $StartTime 0;var $StopTime 0;function get_microtime(){list($usec, $sec) explode( , microtime());return ((float)$usec (float)$sec);}function start(){$this->S…

參數方程求二階偏導_偏微分方程

常微分方程(ODE) 的時候我們更多是關于時間的導數。偏微分方程(partial differential equation) 則不僅僅是與時間相關,加上了與空間位置相關的一些信息。解當 ODE 滿足 利普希茨連續(Lipschitz continuity&#xff09…

Spring Batch 批量處理策略

為了幫助設計和實現批量處理系統,基本的批量應用是通過塊和模式來構建的,同時也應該能夠為程序開發人員和設計人員提供結構的樣例和基礎的批量處理程序。當你開始設計一個批量作業任務的時候,商業邏輯應該被拆分一系列的步驟,而這…

CString原理介紹

看了很多人寫的程序,包括我自己寫的一些代碼,發現很大的一部分bug是關于MFC類中的CString的錯誤用法的.出現這種錯誤的原因主要是對CString的實現機制不是太了解。 CString是對于原來標準c中字符串類型的一種的包裝。因為,通過很長時間的編程&#xff0c…

如何從零開始開發一個 Chrome 插件?

什么是瀏覽器插件?簡單來說瀏覽器插件,是瀏覽器上的一種工具,可以提供一些瀏覽器沒有的功能,幫你做一些有趣的事情。開發者可以根據自己的喜歡,去實現一些功能。插件基于Web技術(html、css、js)…

mysql 重復字段查詢及排除重復值

轉載鏈接:http://blog.sina.com.cn/s/blog_3edc5e2e010131ys.html mysql 重復字段查詢及排除重復值 SELECT a.id,a.title FROM dede_archives a left join dede_taglist t on t.taga.title WHERE t.typeid$id and t.arcrank>-1 and a.typeid28 group by t.tag; …

swiper移入暫停_react中swiper注意事項及鼠標劃入停止輪播

首先是實例化swiper這里有一個注意點,就是實例化的時機如果你的swiper內容是寫死的,可以在componentDidMount中實例化,但是如果你的內容是通過接口異步請求過來的,就必須在componentDidUpdate里實例化,因為如果在 comp…

轉Excel的一種簡單方法

寫了這么久的程序﹐越來越喜歡那種簡單的解決方法﹐這段時間在做一個報表系統﹐其中有需要轉Excel﹐而且要求兼容openoffice﹐遂利用asp語法,asp.net的控件封裝特性以及excel 2003的xml試算清格式做了一個看起來比較"清爽"的excel轉檔方案。一.開始原理很簡單﹐excel…

詳解MySQL中EXPLAIN解釋命令

轉載鏈接:http://database.51cto.com/art/200912/168453.htm explain顯示了mysql如何使用索引來處理select語句以及連接表。可以幫助選擇更好的索引和寫出更優化的查詢語句。 使用方法,在select語句前加上explain就可以了: 如:…

Shell編程基礎

我們可以使用任意一種文字編輯器,比如gedit、kedit、emacs、vi等來編寫shell腳本,它必須以如下行開始(必須放在文件的第一行): # !/bin/sh ...注意:最好使用“!/bin/bash”而不是“!/bin/sh”,…

總結:自學前端的高效學習路線

提到前端,大多數人都會想到薪資高。也正因為如此,很多人想要從事前端開發這個崗位,也由此衍生出來一個問題:為什么前端工程師供不應求,但還是有很多學前端的人找不到工作?其實行業不是缺前端工程師&#xf…

機器人出魔切還是三相_英雄聯盟:輔助也要去上單,機器人布里茨玩法介紹

英雄聯盟:輔助也要去上單,機器人布里茨玩法介紹出裝方面我們都知道他的被動是可以將法力值化為機的護盾的,而這樣的話裝備就可以選擇魔切,然后再出一個鞋子,為什么不先出三項呢?三項的性價比是比較高的&…

vmware創建虛擬機不識別網卡

今天在給虛擬機添加網卡的時候,出現了虛擬機不識別新加的網卡,很納悶,連的一樣的端口組,為什么新加的網卡識別不了呢 然后查看pci設備,發現網卡的驅動為 AMD 79C970 PCnet32- LANCE 然后都vc上查看,果真驅動…

轉:26個Jquery使用小技巧(jQuery tips, tricks solutions)

26個Jquery使用小技巧(jQuery tips, tricks & solutions) 前段時間發布了Jquery類庫1.4版本,使用者也越來越多,為了方便大家對Jquery的使用,下面列出了一些Jquery使用技巧。比如有禁止右鍵點擊、隱藏搜索文本框文字、在新窗口中打開鏈接…

周末包郵送書和小紅包中獎名單公布

大家好,我是若川。周末送福利,給大家送紅包、包郵送新書!這篇文章中,準備了3本自選前端新書,10個2元小紅包,在看抽10人每人5元紅包,2月28日晚8點開獎。現將名單公布如下:在看抽獎&am…

Ubuntu 命令行修改網絡配置方法

轉載鏈接:http://www.jb51.net/article/15807.htm Ubuntu 命令行修改網絡配置方法 /etc/network/interfaces 打開后里面可設置DHCP或手動設置靜態ip。前面auto eth0,讓網卡開機自動掛載. 1. 以DHCP方式配置網卡 編輯文件/etc/network/interfaces: sudo v…

python treeview底部加個按鈕_Python爬取京東商品信息(GUI版本)

前言本文的文字及圖片來源于網絡,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯系我們以作處理。作者:DYblog轉載:https://www.cnblogs.com/dy8888/p/13257918.htmlPS:如有需要Python學習資料的小伙伴可以加點擊…

Linux下編譯安裝Mysql簡單步驟

常規方式編譯安裝MySQL時,適合用第一條最正宗的MySQL產品線5.2及以前版本:所謂常規方式編譯安裝MySQL就是延續早期MySQL的3部曲安裝方式,即./configure;make;make install,下面是老男孩在早期的企業生產場景下操作過的具體命令及參…

Vue.js 3.0 響應式 API 比 2.x 好在哪兒?

Hello,各位小伙伴,接下來的一段時間里,我會把我的課程《Vue.js 3.0 核心源碼解析》中問題的答案陸續在我的公眾號發布,由于課程的問題大多數都是開放性的問題,所以我的答案也不一定是標準的,僅供你參考喔。…

招聘.NET程序員

人才難找啊,順便發個招聘啟事。 西安瀚博科技有限公司招聘.NET程序員,有工作經驗者優先 如有意向,請發郵件到 slzhanghiweb.cn 轉載于:https://www.cnblogs.com/shengli/archive/2010/03/08/1680861.html