摘要:定義調用更改的中的狀態的唯一方法是提交中的非常類似于事件每個都有一個字符串的事件類型和一個回調函數,參數。注意點必須是同步函數原因當觸發的時候,回調函數還沒有被調用。實質上任何在回調函數中進行的狀態的改變都是不可追蹤的。
Vuex
集中式狀態管理
使用時機:
每一個組件都擁有當前應用狀態的一部分,整個應用的狀態是分散在各個角落的。然而經常會需要把把狀態的一部分共享給多個組件。
Vuex:一個專門為Vue.js 應用設計的狀態管理架構.
狀態管理:統一管理和維護各個vue組件的可變化狀態(可以理解成vue組件里的某些data數據,全局變量)
出現背景:
追蹤自定義事件NaN,這個事件由那個組件觸發的,誰在監聽它。
業務邏輯遍布各個組件,導致各種意想不到的問題。
由于要顯式的分發和監聽,父組件和子組件強耦合
Vuex 核心概念:
狀態樹:包含所有應用層級狀態。意味著,每個應用將僅僅包含一個store實例。單狀態樹能夠直接定位任意特定的狀態片段。
Getters:在Vue組件內部獲取stroe中狀態/數據的函數
Mutations:通過事件回調函數來修改store中的狀態的變化.
Actions:在組件內部使用函數,分發mutations事件的函數.
為什么需要有action
每一個web應用都至少對應一個數據結構,而導致這個數據結構狀態更新的來源很豐富;光是用戶對view的操作(dom事件)就有幾十種,此外還有ajax獲取數據、路由/hash狀態變化的記錄和跟蹤。
來源豐富不是最可怕的,更可怕的是每個來源提供的數據結構并不統一。DOM事件還好,前端可以自主控制與設計;ajax獲取的數據,其結構常常是服務端開發人員說了算,面對業務場景跟前端并不相同,往往會為了自己的便利,給出在前端看來很隨意的數據結構。
web應對中所有的數據與狀態的變化,幾乎都來自[事件],DOM事件,AJAX成功或失敗事件,路由change事件,setTimeout定時器事件,以及自定義事件。任意時間都可能產生需要合并全局數據對象里的新數據或者線索。
是event響應函數里主動調用了action函數,并且傳入它需要的數據。
action 作用:
action 是專門用來被component調用的函數
action函數能夠通過分發相應的mutation函數, 來觸發對stroe的更新
action 可以先從HTTP后端 或 store 中讀取其它數據之后再分發更新事件
Vuex把狀態分為:
組件本地狀態
僅在一個組件內使用的狀態(data字段)應用層級狀態(應用級的狀態不屬于任何特定的組件,但每一個組件仍然可以監視其變化從而響應式的更新DOM)
組件內部使用的狀態,通過配置選項傳入Vue組件內部的意思。
應用級別狀態
多個組件共用的狀態
同時被多個組件共享的狀態層級
Vuex 應用的核心是store(倉庫)理解成項目中使用的數據的集合。 包含著大部分的狀態(即state)
Vuex和單純的全局對象:
Vuex的狀態存儲是響應式的。當Vue組件從store中讀取狀態的時候,若store中的狀態發生變化。
不能截至改變store中的狀態。改變store中的狀態的唯一途徑就是顯示地分發 狀態變更事件
作用:方便的跟蹤每一個狀態的變化。
vuex 把應用的數據和修改的數據的方法,放在了一個 sotre 對象里面統一管理,對數據的獲取和操作則分別通過 vm新增的配置屬性 vuex 的 getters 和 actions 來進行
整個APP的數據就是存放在state對象里,隨取隨用.
定義一個mutations對象。可以把mutations理解為“用于改變state狀態的一系列方法”
在vuex的概念里,state僅能通過mutations修改。
好處:能夠更直觀清晰的集中管理應用的狀態。
數據流動是單向
組件可以調用actions
Actions是用來分發 mutations
只有mutations可以修改狀態
store是反應式(狀態的變化會在組件內部得到反映)
sotre只需要在最頂層的組件聲明一次
在入口文件加入:
var store = new Vuex.Store({ state: { a: false, money: 0 }, mutations: { increment( state ) { store.state.a; } } });
組件中使用:
computed: { a: function() { return store.state.a; } }
使用Vuex遵守規則:
應用層級的狀態應該幾種到單個sotre對象中。
提交mutation是更改狀態的唯一方法,并且這個過程是同步的。
異步邏輯都應該封裝到action里面。
State單一狀態樹
Vuex 使用 單一狀態樹。 使用一個對象包含全部的應用層級狀態(數據)。把它作為一個唯一數據源提供方存在(全局變量)。
每個應用程序僅僅包含一個store實例。單狀態數能夠直接定位任意特定的狀態片段,在調試過程中能夠輕易的獲取整個當前應用狀態。(單狀態樹和模塊化并不沖突)
Vuex 中數據都是單向的,Vue組件只能從 store獲取。
如何在Vue組件中獲得Vuex狀態
由于 Vuex 的狀態存儲是響應式的,從 store 實例中 讀取狀態在計算屬性computed 中返回某個狀態。
new Vue({ el: ".app", computed: { count: function () { return stroe.state.count; } } });
store.state特性:
每當store.state.count變化的時候,都會重新求取計算屬性,并且觸發更新相關的DOM。
導致組件過度依賴全局狀態單例。
每個模塊化的組件中,需要頻繁導入,并且在測試組件時需要模擬狀態。
組件仍然保有局部狀態
使用Vuex并不意味著需要將所有的狀態放入Vuex。
優點:把所有狀態放入Vuex會是的狀態變化更顯式和易調試。
缺點:代碼變得冗長和不直觀。
如果有些狀態嚴格屬于單個組件,最好還是作為組件的局部狀態。
Getters需要對數據進行第二次加工處理,全局函數處理,可以在 store中定義getters(可以認為store的計算屬性)。
定義
const store = new Vue({ state: { list: [{id: 1, text: "a"}, {id: 2, text: "b"}] }, getters: { done: state => { return state.todos.filter(todo => todo.done); } } });
調用
store.getters.lenCountMutations
更改Vuex的store中的狀態的唯一方法是提交 mutation.
Vuex中的mutations非常類似于事件:每個mutations都有一個字符串的 事件類型(type) 和 一個回調函數(handler),參數:state。
定義
const store = new Vue.store({ state: { a: 0 }, mutations: { heade( state ) { state.a += 10; } } });
調用
sotre.commit("heade");
傳入多個參數(提交載荷Payload) 多數情況下,另外的參數,會是對象。
// 定義 mutations: { heade( state, n ) { state.a += n; } } // 調用 store.commit("heade", 100);
Mutations 需遵守 Vue 的響應規則
Vuex中的store中的狀態是響應式的,變更狀態時,監聽狀態的Vue組件也會自動更新。
注意:
最好提前在sotre中出初始化好所有所需屬性。
當需要在對象上添加新屬性時,應該使用Vue.set(obj, "newProp", 123) 或者 以新對象替換老對象。
使用常量替代Mutation事件類型
使用常量替代mutation事件類型在各種 Flux 實現中常見模式.
結果:可以使linter之類的工具發揮作用,同時把這些常量放在多帶帶的文件中可以讓代碼合作者對這個app包含的mutation清晰明了。
// mutation-types.js export const FETCH_MOVIE_BY_ID = "FETCH_MOVIE_BY_ID"; // store.js import Vuex form "vuex"; import {FETCH_MOVIE_BY_ID} from "./mutations-types.js"; const store = new Vuex.Store({ state: {}, mutations: { ["FETCH_MOVIE_BY_ID"]( state ) { // mutate state } } });
mutation注意點:
mutation必須是同步函數
原因:當mutation觸發的時候,回調函數還沒有被調用。 實質上任何在回調函數中進行的狀態的改變都是不可追蹤的。
在組件中提交Mutations
定義:
increment: function( context ) { context.a += 10; }
使用方式:
// 方式1 store.commit("increment"); // this.$store.commit("xxx") // 方式2 methods: { mapMutations(["increment"]) // // 映射 this.increment() 為 this.$store.commit("increment") }Actions
Actions類似于mutations,不同點:
Actions 提交的是mutation,而不是直接變更狀態。
Actinos 可以包含任意異步操作。
store = new Vuex.Store({ state: { a: 0 }, mutations: { add() { state.a += 10; } }, actions: { add( context ) { context.commit("add"); } } });
Action 函數參數:store實例具有相同的方法和屬性的context對象。
可以調用context.commit(); 執行一個mutation。 或者通過context.state 和 context.getters 來獲取 state和 getters。
分發Action
Action通過store.dispatch方法觸發.
store.dispatch();
Action 能夠支持載荷方式和對象方式進行分發.
// 以載荷形式分發 store.dispatch("add", { amount: 10 }) // 以對象形式分發 store.dispatch({ type: "add", amount: 10 })
在組件中分發Action
定義:
increment: function( context ) { context.a += 10; }
使用方式:
// 方式1 store.dispatch("increment"); // this.$store.dispatch("xxx") // 方式2 methods: { mapActions(["increment"]) // // 映射 this.increment() 為 this.$store.commit("increment") }
組合Actions
Action 通常是異步,如何知道action 什么時候結束。如何組合多個action,以處理更加復雜的異步流程?
store.dispatch的返回的是被處罰的action函數的返回值,因為,可以在action中返回Promise
actions: { actionA({commit}) { return new Promise((resolve, reject) => { setTimeout(() => { commit("someMutation"); resolve(); }, 1000) }) }, actionB({dispatch}) { return dispatch("actionA").then(()=>{ commit("someOhterMutation"); }) } }
一個sotre.dispatch()在不同模塊中可以出發多個action函數。在當前情況下,只有當所有觸發函數完成后,返回的Promise才會執行。
案例:
import * as types from "../types"; import {fetchMoviesByType, fetchSearchMovies, fetchMovieById} from "../api"; const state = { movies: [], movieList: { title: "", total: 0, subjects: [], }, busy: false, movie: {}, }; const actions = { [types.FETCH_MOVIES](context,payload){ fetchMoviesByType(payload.type, payload.start, payload.count) .then(data=>{ data.type = payload.type; return context.commit([types.FETCH_MOVIES], data) }); }, [types.FETCH_MOVIE_LIST](context,payload){ fetchMoviesByType(payload.type, payload.start) .then(data=>context.commit([types.FETCH_MOVIE_LIST], data)); }, [types.FETCH_MOVIE_BY_ID](context, id){ fetchMovieById(id) .then(data => context.commit([types.FETCH_MOVIE_BY_ID], data)); }, [types.SET_INFINITE_BUSY](context, data){ context.commit([types.SET_INFINITE_BUSY], data); }, [types.CLEAN_MOVIE](context){ context.commit(types.CLEAN_MOVIE); }, [types.CLEAN_MOVIES](context){ context.commit([types.CLEAN_MOVIES]) }, [types.CLEAN_MOVIE_LIST](context){ context.commit([types.CLEAN_MOVIE_LIST]) } }; const mutations = { [types.FETCH_MOVIES](state, list){ state.movies.push(list); }, [types.FETCH_MOVIE_LIST](state, list){ state.movieList.title = list.title; state.movieList.total = list.total; state.movieList.subjects = state.movieList.subjects.concat(list.subjects); if(state.movieList.subjects.length < state.movieList.total){ state.busy = false; } }, [types.FETCH_MOVIE_BY_ID](state, movie){ state.movie = movie; }, [types.SET_INFINITE_BUSY](state, data){ state.busy = data; }, [types.CLEAN_MOVIE](state){ state.movie = {}; }, [types.CLEAN_MOVIES](state){ state.movies = []; }, [types.CLEAN_MOVIE_LIST](state){ state.movieList = {}; } }; export default { state, mutations, actions }
`api.js` 發送ajax // 定義ajax事件 `modules/movie.js` 中寫 state,mutations,actions // action 中執行ajax定義事件, 回調函數中執行mutations中定義的事件 `mutations` 定義事件, 第一個參數是`context`,當前定義的store `types.js` 定義常量替代mutation事件類型
// src/components/header.vue // 從vuex拿數據,然后渲染到頁面上 // 如果需要修改可以調用setTitle import { setTitle } from "../vuex/actions"; export default { vuex: { // 獲取vuex狀態數據 getters: { title: state => state.title, info: ({index}) => index.info }, // 狀態變更事件 actions: { setTitle } } }Modules
場景:使用單一狀態數,導致應用的所有狀態集中到一個很大的對象。但是,當應用變得很大時,sotre對象會變得難以維護。
Vuex允許將sotre分割到模塊(module),每個模塊擁有自己的state,mutation,action,getters.
import Vuex from "vuex" import Vue from "vue" import movie from "./modules/movie" Vue.use(Vuex); export default new Vuex.Store({ modules: { movie } });Store配置項
new Vuex.Store({ state: {}, // 初始狀態 actions: {}, // 執行 mutation,異步. getters: {}, // 全局方法,二次加工數據 mutations: {} // Store 與外界交互的入口 });
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87920.html
閱讀 2784·2023-04-25 18:06
閱讀 2576·2021-11-22 09:34
閱讀 1684·2021-11-08 13:16
閱讀 1302·2021-09-24 09:47
閱讀 3049·2019-08-30 15:44
閱讀 2773·2019-08-29 17:24
閱讀 2584·2019-08-23 18:37
閱讀 2433·2019-08-23 16:55