個人自學前端27-Vue4-狀態管理
阿新 • • 發佈:2021-10-07
目錄
一.狀態管理
假設當一個數據變化時,多個元件同時更新檢視. => 狀態管理 => 應該把資料放到多個元件的共同祖先元件上
什麼叫狀態? => 狀態就是響應式資料和呈現它的檢視.
元件的狀態是由它的資料和檢視決定的.
狀態管理 => 資料和檢視管理.
狀態管理 => 如何實現多個元件共用一個狀態?
- 把資料和修改資料的邏輯放在父元件上.子元件通過props獲取父元件資料,再通過自定義事件觸發父元件修改資料的邏輯.(父傳子,子傳父)
- Vuex.(Vue的外掛 => Vue的全域性狀態管理)
二.Vuex
Vuex如何實現:
- 如何例項化Vuex資料倉庫.(用於存放資料和修改資料的邏輯)
- 元件如何獲取Vuex的資料
- 元件如何修改Vuex的資料
- 如何把Vuex的資料和邏輯對映成元件的資料和邏輯
1. 如何例項化Vuex資料倉庫.(用於存放資料和修改資料的邏輯)
例項化一個數據倉庫.例項化之後,還需要掛載到Vue例項上.
掛載到new Vue上,就是全域性的狀態管理。所有的元件,都可以訪問到state內的資料。
如果掛載到指定的元件A上,則元件A以及元件A的所有子孫元件,都可以訪問到state內的資料。
// 例項化一個數據倉庫
const store = new Vuex.Store({
// 多個元件共用的狀態.(資料)
state: {
count: 0
}
})
new Vue({
el: '#app',
components: {App},
template: `<App />`,
// store: store
// 掛載store
store
});
2. 元件如何獲取Vuex的資料
掛載完成後,就可以通過Vuex的例項store來訪問state內的資料。
vue元件內可以通過this.$store來獲取這個state的例項。
const box = {
template: `
<div>
<h3>box元件---{{count}}</h3>
<button>box--count++</button>
</div>
`,
computed: {
count() {
// 獲取state的例項
return this.$store.state.count
}
},
}
3. 元件如何修改Vuex的資料
- 修改state資料的邏輯,需要通過mutations選項寫在資料倉庫中,可以寫多個方法.
mutations內的方法的第一個引數是state物件,第二個引數是元件傳遞的引數.
元件觸發mutations內的方法,需要同this.$store.commit來觸發.
commit('mutation的方法名', 元件實參);
const store = new Vuex.Store({
// 多個元件共用的狀態.(資料)
state: {
count: 10000
},
// 修改state內資料的邏輯.
mutations: {
// count+1
plus(state, num) {
state.count += num;
},
// count-1
reduce(state, num) {
state.count -= num
}
}
});
const box = {
template: `
<div>
<h3>box元件---{{count}}</h3>
<button @click='$store.commit("plus", 1)'>box--count++</button>
<button @click='$store.commit("reduce", 1)'>box--count--</button>
</div>
`,
computed: {
count() {
return this.$store.state.count
}
},
}
- 如果有非同步操作的需求,需要通過actions來實現
actions方法內觸發mutations方法.
actions的觸發方式是dispatch.
dispatch('actions的方法名', 元件實參);
const store = new Vuex.Store({
// 嚴格模式.禁止在mutations之外修改state.
// 如果在mutations之外修改state,會報這個錯[vuex] do not mutate vuex store state outside mutation handlers.
strict: true,
// 多個元件共用的狀態.(資料)
state: {
count: 10000
},
// 修改state內資料的邏輯.
mutations: {
// count+1
plus(state, num) {
state.count += num
},
// count-1
reduce(state, num) {
state.count -= num
}
},
// 非同步觸發mutations
actions: {
asyncPlus(store, num) {
// 2秒後觸發mutations的plus方法修改state。
setTimeout(() => {
store.commit("plus", num);
}, 2000);
}
}
});
const box = {
template: `
<div>
<h3>box元件---{{count}}</h3>
<button @click='$store.dispatch("asyncPlus", 1)'>box--count++</button>
<button @click='$store.commit("reduce", 1)'>box--count--</button>
</div>
`,
computed: {
count() {
return this.$store.state.count
}
},
}
4. 如何把Vuex的資料和邏輯對映成元件的資料和邏輯
map對映:
- 把state的資料變成元件資料.
- 把mutations和actions的方法變成元件方法.
const { mapState, mapMutations, mapActions } = Vuex;
// 以上這些方法,都是返回純物件的.
// mapState(['count', 'msg']) => { count() {} , msg() {}}
const box = {
template: `
<div>
<h3>box元件---{{num}}---{{str}}</h3>
<button @click='$store.dispatch("asyncPlus", 1)'>box--count++</button>
<button @click='$store.commit("reduce", 1)'>box--count--</button>
</div>
`,
computed: {
// count() {
// return this.$store.state.count
// }
// msg() {
// return this.$store.state.msg
// }
// ...mapState(['count', 'msg'])
...mapState({
num: 'count',
str: 'msg'
})
},
methods: {
...mapActions(['asyncPlus']),
...mapMutations(['reduce'])
}
}
5.Vuex的計算屬性getters
<script>
const { mapState, mapMutations, mapGetters } = Vuex;
const store = new Vuex.Store({
state: {
count: 1,
price: 10,
},
// Vuex的計算屬性total
getters: {
total({count, price}) {
return count * price
}
},
mutations: {
setCount(state, val) {
state.count = val
},
setPrice(state, val) {
state.price = val
}
}
});
const mx = {
computed: {
...mapState(['count', 'price'])
},
methods: {
...mapMutations(['setCount', 'setPrice'])
}
}
const count = {
template: `<input type='text' placeholder='數量' :value='count' @input='setCount($event.target.value)' />`,
mixins: [mx]
}
const price = {
template: `<input type='text' placeholder='單價' :value='price' @input='setPrice($event.target.value)' />`,
mixins: [mx]
}
const total = {
template: `<div>總價:{{total}}</div>`,
computed: {
// total() {
// 通過$store來獲取Vuex的計算屬性.
// return this.$store.getters.total
// }
// 通過對映方法快速引入Vuex的計算屬性total
...mapGetters(['total'])
}
}
const App = {
template: `
<div>
<count />
<price />
<total />
</div>
`,
components: {count, price, total},
store
}
new Vue({
el: '#app',
components: { App },
template: `<App />`
})
</script>
6. Vuex的資料流
Vuex是如何讓多個元件同時更新的?
- 例項化Vuex的過程中,Vue會給state內的資料都新增資料劫持.
- 通過掛載store例項,就可以知道當state內的資料變化時,應該更新多少個元件.(收集依賴).
- 每當state內的資料變化,都會更新對應元件的檢視.
元件按鈕 => actions(dispatch) => mutations(commit) => state => 自動通知對應的檢視更新.
7. 總結
1:例項化,掛載
new Vuex.Store({
strict: true => 不允許在mutations之外修改資料
state: {} => 多個元件共用的資料(狀態)
mutations => 修改state內資料的邏輯
actions => 非同步觸發mutations的方法
getters => state的計算屬性
});
掛載 => 可以掛載到任意元件上.掛到new Vue上,就是全域性狀態管理.
掛到元件A上,則A元件和A元件的所有子孫元素都可以共享Vuex的資料.
2:獲取資料
$store.state.資料名
computed: {
資料名() {
return this.$store.state.資料名
}
}
3:修改資料
沒有非同步 => 直接commit觸發mutations
有非同步 => 先通過dispatch觸發actions,actions再觸發mutations.
4:對映
mapState, mapMutations, mapActions, mapGetters