Vue四、vuex是個(gè)啥埋涧?怎么用贴唇?

vuex官方文檔

一、vuex是什么

官方解釋是:Vuex是通過全局注入store對(duì)象飞袋,來實(shí)現(xiàn)組件間的狀態(tài)共享,是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式链患。

我的理解是巧鸭,例如你的項(xiàng)目里某一個(gè)數(shù)據(jù)在前端多個(gè)組件中都有應(yīng)用,如果一個(gè)改的話麻捻,那豈不是每個(gè)組件都需要改一次纲仍,特別是類似的數(shù)據(jù)多起來的話呀袱,操作起來想想就繁雜,于是郑叠,可以通過Vuex來實(shí)現(xiàn)組件間的狀態(tài)共享夜赵,改一個(gè),其他組件中的值的狀態(tài)自動(dòng)改變乡革。

* 那么可能有人問:直接用全局對(duì)象不久可以了寇僧?

Vuex 和單純的全局對(duì)象有以下兩點(diǎn)不同:

  1. Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候沸版,若 store 中的狀態(tài)發(fā)生變化嘁傀,那么相應(yīng)的組件也會(huì)相應(yīng)地得到高效更新。
  2. 你不能直接改變 store 中的狀態(tài)视粮。改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation细办。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化,從而讓我們能夠?qū)崿F(xiàn)一些工具幫助我們更好地了解我們的應(yīng)用蕾殴。

* 那么可能有人問:Vuex與localStorage不一樣么笑撞?

vuex 是 vue 的狀態(tài)管理器,存儲(chǔ)的數(shù)據(jù)是響應(yīng)式的钓觉,但是并不會(huì)保存起來茴肥,刷新之后就回到了初始狀態(tài),但是localStorage是保存在瀏覽器中的议谷,刷新之后還可以取出來繼續(xù)使用炉爆。而且,vuex里卧晓,我們保存的一般都是數(shù)組芬首,而localStorage保存到話只支持字符串

* 那么可能有人問:既然是存數(shù)據(jù)的,那什么時(shí)候用vuex逼裆,什么時(shí)候直接用簡(jiǎn)單的通信方式哩郁稍?

  • 如果項(xiàng)目足夠簡(jiǎn)單(只是多個(gè)組件間傳遞數(shù)據(jù)),最好不要使用 Vuex胜宇。一個(gè)簡(jiǎn)單的 store 模式就足夠所需了耀怜,只使用組件間常用的通信方法即可,使用 Vuex 可能是繁瑣冗余的桐愉。

Vue組件簡(jiǎn)單常用的通信方式有以下幾種:
1财破、父向子傳值通過props的方式;
2从诲、子向父傳值通過events ($emit)左痢,實(shí)際上就是子組件把自己的數(shù)據(jù)發(fā)送到父組件;
3、父調(diào)用子方法通過ref俊性;provide / inject略步。
4、兄弟之間通信通過bus
5定页、跨級(jí)嵌套通信可以使用bus趟薄;provide / inject等。
6典徊、 vue組件間通信六種方式(完整版)

  • 如果需要構(gòu)建一個(gè)中大型單頁應(yīng)用(多級(jí)組件嵌套)杭煎,一個(gè)組件更改某個(gè)數(shù)據(jù),多個(gè)組件自動(dòng)獲取更改后的數(shù)據(jù)進(jìn)行業(yè)務(wù)邏輯處理宫峦,Vuex 將會(huì)成為自然而然的選擇岔帽。
vuex的構(gòu)成
  • 由上面官方給的圖可以看出vuex由以下幾部分構(gòu)成
    1. State
    state是存儲(chǔ)的單一狀態(tài),是存儲(chǔ)的基本數(shù)據(jù)导绷。對(duì)象必須是純粹的對(duì)象 (含有零個(gè)或多個(gè)的 key/value 對(duì))犀勒。它作為一個(gè)“唯一數(shù)據(jù)源 (SSOT)”而存在。
    2. Mutation
    更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation更改數(shù)據(jù)【必須是同步函數(shù)】妥曲。(使用store.commit方法更改state存儲(chǔ)的狀態(tài))
    3. Action
    Action 類似于 mutation贾费,不同在于:
    Action 提交的是 mutation,而不是直接變更狀態(tài)檐盟。
    Action 可以包含任意【異步操作】褂萧。
    Action 通過 store.dispatch 方法觸發(fā),Mutation使用store.commit觸發(fā)葵萎。
    4. Getter
    getters是store的計(jì)算屬性导犹,可以通過store 中的 state 中派生出一些狀態(tài)(比如說過濾)。就像computed計(jì)算屬性一樣羡忘,getter返回的值會(huì)根據(jù)它的依賴被緩存起來谎痢,且只有當(dāng)它的依賴值發(fā)生改變才會(huì)被重新計(jì)算。
    5. Module
    當(dāng)應(yīng)用變得復(fù)雜時(shí)卷雕,store對(duì)象可能變得相當(dāng)臃腫復(fù)雜节猿。為了解決這個(gè)問題,Vuex 允許我們將 store 分割成模塊(module)漫雕。每個(gè)模塊擁有自己的 state滨嘱、mutation、action浸间、getter太雨、甚至是嵌套子模塊——從上至下進(jìn)行同樣方式的分割:
const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)

* 所以vuex的是怎么運(yùn)行的?

  • vuex的運(yùn)行流程
  1. 在組件內(nèi)部魁蒜,通過dispatch來分發(fā)action囊扳。
  2. 再通過action來第調(diào)用mutation
  3. 進(jìn)而觸發(fā)mutation內(nèi)部的commit來修改state
  4. 最后state改變煤墙,導(dǎo)致頁面重新render。

二宪拥、vuex怎么用

1.安裝

NPM
npm install vuex --save
Yarn
yarn add vuex

2.中型數(shù)據(jù)不太復(fù)雜的項(xiàng)目中(直接使用)

其實(shí)使用cli工具初始化的項(xiàng)目中如果選擇安裝vuex的話就已經(jīng)有了。如下:
src文件夾中新建一個(gè)store文件夾铣减,下面新建一個(gè)名為index.js的文件她君。如下

src文件夾下

index.js中注冊(cè)vuex,并且在state中初始化
一個(gè)count變量介紹mutations
一個(gè)tasks數(shù)組 + 一個(gè)taskFinish方法介紹getters
一個(gè)increment方法介紹actions

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: { 
      count:0,
      tasks: [
         { id: 1, finish: true },
         { id: 2, finish: false }
      ]
 },
  mutations: {
      // 更改 Vuex 的 store 中的狀態(tài)的唯一方法
     countAdd (state) {
            // 自定義將傳過來的參數(shù)操作操作
            state.count++
           }
  },
  getters: {
        // getters是store的計(jì)算屬性葫哗, 有時(shí)候需要從  store 中的 state 中派生出一些狀態(tài)(比如說過濾)
       taskFinish: state => {
              return state.tasks.filter(a=> a.finish)
    }
   },
  actions: { 
         // actions 提交的是 mutation缔刹,而不是直接變更狀態(tài).
        increment(context) {
            context.commit('countAdd')
          }
  },
  modules: {}
});

main.js中導(dǎo)入store實(shí)例,我們就可以通過this.$store.state訪問這些狀態(tài)劣针,一般把它的值注入到computed

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

// 阻止啟動(dòng)生產(chǎn)消息校镐,常用作指令 ?
Vue.config.productionTip = false;

new Vue({
  router,
  store,   // 注冊(cè),全局使用vuex捺典,(this.$store)
  render: h => h(App)
}).$mount("#app");

在后綴名為.vue的組件中使用

  • this.$store.state.count實(shí)現(xiàn)數(shù)據(jù)調(diào)用
  • this.$store.commit('countAdd')實(shí)現(xiàn)通過mutations實(shí)現(xiàn)數(shù)據(jù)修改(同步方式)
  • this.$store.getters.taskFinish實(shí)現(xiàn)通過getters實(shí)現(xiàn) state 中的數(shù)據(jù)派生出一些狀態(tài)(過濾數(shù)據(jù))
<!-- 測(cè)試項(xiàng)目 -->
<template>
  <div>      
        <h3>{{this.$store.state.count}}</h3>
        <h4>{{this.$store.getters.taskFinish}}</h4>
        <input type="button" value="count自增"  @click="countAdd"></div>
        <button @click="increment">按鈕</button>
</template>

<script>
export default {
  data() {
    return {};
  },

  components: {},

  computed: {},

  mounted() {},

  methods: {
       countAdd() {
            // commit不僅可以傳state的參數(shù)鸟廓,而且可以傳額外的參數(shù),只需在mutations里定義的函數(shù)后面的參數(shù)里與這里的一致就可以
            this.$store.commit('countAdd')
        },
       increment(){
            // 效果跟countAdd()是一樣的
            this.$store.dispatch('increment')
        }
  }
};
</script>
<style>
</style>

* 看完例子之后可能有人說了襟己,mutations和action效果不是一樣的么引谜,直接使用mutations不就行了,何必再用action做一次類似于請(qǐng)求轉(zhuǎn)發(fā)的操作呢擎浴?

:實(shí)際上并非如此员咽。還記得 mutation 必須同步執(zhí)行這個(gè)限制么?Action 就不受約束贮预!我們可以在 action 內(nèi)部執(zhí)行異步操作

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

Actions 支持同樣的載荷方式對(duì)象方式進(jìn)行分發(fā):

// 以載荷形式分發(fā)
store.dispatch('incrementAsync', {
  amount: 10
})

// 以對(duì)象形式分發(fā)
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

當(dāng)然這些方法只是簡(jiǎn)單的介紹理解一下vuex里面的東西贝室,深入理解還需要自己實(shí)際寫一下去探索。上面輸出的格式可以簡(jiǎn)化仿吞,例如
this.$store.state.count放入computed計(jì)算屬性當(dāng)中去

export default {
 name: 'App',
  computed:{
       count(){
           return this.$store.state.count;
       }
   }
}

然后直接通過<h3>{{count}}</h3>調(diào)用即可

3.大型數(shù)據(jù)密集型項(xiàng)目中使用(需要將其劃分為模塊使用)

方法一:src文件夾中新建一個(gè)store文件夾滑频,下面分別新建名為index.js / actions.js / getter.js / mutations.js的文件。

store文件夾下

方法一例子來自于vuex最詳細(xì)完整的使用用法茫藏,讓大家知道每個(gè)文件里的內(nèi)容的格式

index.js


import Vue from 'vue'
import Vuex from 'vuex'
import * as getters from './getters' // 導(dǎo)入相應(yīng)的模塊误趴,*相當(dāng)于引入了這個(gè)組件下所有導(dǎo)出的事例,使用*和from關(guān)鍵字來實(shí)現(xiàn)的模塊的繼承
import * as actions from './actions'
import * as mutations from './mutations'
 
Vue.use(Vuex)
// 首先聲明一個(gè)需要全局維護(hù)的狀態(tài) state,比如 我這里舉例的resturantName
const state = {
    resturantName: '飛歌餐館' // 默認(rèn)值
    // id: xxx  如果還有全局狀態(tài)也可以在這里添加
    // name:xxx
}
 
// 注冊(cè)上面引入的各大模塊
const store = new Vuex.Store({
    state,    // 共同維護(hù)的一個(gè)狀態(tài)务傲,state里面可以是很多個(gè)全局狀態(tài)
    getters,  // 獲取數(shù)據(jù)并渲染
    actions,  // 數(shù)據(jù)的異步操作
    mutations  // 處理數(shù)據(jù)的唯一途徑凉当,state的改變或賦值只能在這里
})
 
export default store  // 導(dǎo)出store并在 main.js中引用注冊(cè)。

actions.js

// 給action注冊(cè)事件處理函數(shù)售葡。當(dāng)這個(gè)函數(shù)被觸發(fā)時(shí)候看杭,將狀態(tài)提交到mutations中處理
export function modifyAName({commit}, name) { // commit 提交;name即為點(diǎn)擊后傳遞過來的參數(shù)挟伙,此時(shí)是 'A餐館'
    return commit ('modifyAName', name)
}
export function modifyBName({commit}, name) {
    return commit ('modifyBName', name)
}
 
// ES6精簡(jiǎn)寫法
// export const modifyAName = ({commit},name) => commit('modifyAName', name)

mutations.js

// 提交 mutations是更改Vuex狀態(tài)的唯一合法方法
export const modifyAName = (state, name) => { // A組件點(diǎn)擊更改餐館名稱為 A餐館
    state.resturantName = name   // 把方法傳遞過來的參數(shù)楼雹,賦值給state中的resturantName
}
export const modifyBName = (state, name) => { // B組件點(diǎn)擊更改餐館名稱為 B餐館
    state.resturantName = name
}

getters.js

// 獲取最終的狀態(tài)信息
export const resturantName = state => state.resturantName

在后綴為.vue的文件中

像上面一樣類似操作

方法二:新建一個(gè)名為modules的文件夾,modules文件夾下面分別新建自己對(duì)應(yīng)需要的模塊。

store文件夾下

每一個(gè)modules文件夾下的文件里

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

moudel.exports = moduleA 

index.js中注冊(cè)使用的話


import Vue from 'vue'
import Vuex from 'vuex'
import * as getters from './modules/cart' // 導(dǎo)入相應(yīng)的模塊贮缅,使用*和from關(guān)鍵字來實(shí)現(xiàn)的模塊的繼承
import * as  ...
 
Vue.use(Vuex)

// 注冊(cè)上面引入的各大模塊
const store = new Vuex.Store({
   modules: {
    a: moduleA,
    ...
  } 
})
 
export default store  // 導(dǎo)出store并在 main.js中引用注冊(cè)榨咐。

使用:

store.state.a.xx // -> moduleA 的狀態(tài)

4.一些思考

(1)、vuex中的設(shè)計(jì)理念谴供?為什么能實(shí)現(xiàn)各個(gè)組件間數(shù)據(jù)的監(jiān)聽块茁?

(2)、vuex是如何實(shí)現(xiàn)在各個(gè)組件中桂肌,store里面的數(shù)據(jù)以響應(yīng)的方式來實(shí)現(xiàn)實(shí)時(shí)跟新的数焊?

(3)、vuex中的那些commit 崎场,dispatch方法以及各種語法糖佩耳,更深層次是如何實(shí)現(xiàn)的?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谭跨,一起剝皮案震驚了整個(gè)濱河市干厚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饺蚊,老刑警劉巖萍诱,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異污呼,居然都是意外死亡裕坊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門燕酷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來籍凝,“玉大人,你說我怎么就攤上這事苗缩《伲” “怎么了?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵酱讶,是天一觀的道長(zhǎng)退盯。 經(jīng)常有香客問我,道長(zhǎng)泻肯,這世上最難降的妖魔是什么渊迁? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮灶挟,結(jié)果婚禮上琉朽,老公的妹妹穿的比我還像新娘。我一直安慰自己稚铣,他們只是感情好箱叁,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布墅垮。 她就那樣靜靜地躺著,像睡著了一般耕漱。 火紅的嫁衣襯著肌膚如雪算色。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天螟够,我揣著相機(jī)與錄音剃允,去河邊找鬼。 笑死齐鲤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的椒楣。 我是一名探鬼主播给郊,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼捧灰!你這毒婦竟也來了淆九?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤毛俏,失蹤者是張志新(化名)和其女友劉穎炭庙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體煌寇,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡焕蹄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阀溶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腻脏。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖银锻,靈堂內(nèi)的尸體忽然破棺而出永品,到底是詐尸還是另有隱情,我是刑警寧澤击纬,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布鼎姐,位于F島的核電站,受9級(jí)特大地震影響更振,放射性物質(zhì)發(fā)生泄漏炕桨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一殃饿、第九天 我趴在偏房一處隱蔽的房頂上張望谋作。 院中可真熱鬧,春花似錦乎芳、人聲如沸遵蚜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吭净。三九已至睡汹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寂殉,已是汗流浹背囚巴。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留友扰,地道東北人彤叉。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像村怪,于是被迫代替她去往敵國(guó)和親秽浇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348