Vue复习五(vuex)
vuex
状态管理模块
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
count: 0,
num:2
},
mutations: {
increment (state) {
state.count++
},
add(state) {
state.num++
}
}
})
导入mian.js
import './components/vuex'
import {store} from './components/vuex'
new Vue({
render: h => h(App),
router,
store
}).$mount('#app')
页面上使用
this.$store.state.count
mapState
computed: {
localComputed () { /* ... */ },
...mapState({
count: state => state.count,
// 'count' 和 `state => state.count` 结果相同
countAlias: 'count',
// to access local state with `this`, a normal function must be used
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
如果是数组的话
[
// 映射 this.count 为 store.state.count
'count'
]
getter (类似计算属性)
类似于store 的计算属性
getters: {
// 第二个参数传递其他的getters
doneTodos: ({todos}, {numAdd}) => {
console.log(numAdd); //3
return todos.filter(todo => todo.done)
},
numAdd: ({num}) => {
return num + 1
}, //方法的形式的访问
getTodoBy: (state) => id => {
return state.todos.find(todo => todo.id === id)
}
}
使用
store.getters.getTodoBy(2)
store.numAdd
mapGetters
computed: {
...mapGetters([
'numAdd' ,
'doneTodos',
'getTodoBy'
])
},
对象的形式
...mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
Mutation(类似事件)
Vuex 中的 mutation 非常类似于事件
mutations: {
// 第二个是传递的参数,可以是基本数据类型也可以复杂
increment(state, n) {
return state.num + n
}
},
this.$store.commit('increment',20)
提交方式
store.commit({
type: 'increment', // 方法
amount: 10 //后面的传递参数
})
整个对象都作为载荷传给 mutation 函数
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
响应式规则
- 最好提前在你的 store 中初始化好所有所需属性。
- 当需要在对象上添加新属性时,你应该
-
使用
Vue.set(obj, 'newProp', 123)
, 或者 -
以新对象替换老对象。
state.obj = { ...state.obj, newProp: 123 }
常量替代Mutation 事件类型
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
mutations: {
// 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
[SOME_MUTATION] (state) {
// mutate state
}
}
mutation 是同步函数的
mapMutations
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
Action
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increase(state) {
state.count++;
}
},
actions: {
increase(context) {
context.commit("increase");
},
increment ({ commit }) {
commit('increment')
}
}
});
触发
store.dispatch('increment')
传递参数
// 以载荷形式分发
store.dispatch('incrementAsync', {
amount: 10
})
// 以对象形式分发
store.dispatch({
type: 'incrementAsync',
amount: 10
})
方法的操作不同
vuex的处理方式是同步在mutation里面,异步在actions里面
因为异步操作是成功还是失败不可预测,什么时候进行异步操作也不可预测;当异步操作成功或失败时,如果不 commit(mutation) 或者 dispatch(action),Vuex 和 Redux 就不能捕获到异步的结果从而进行相应的操作
action
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
store.dispatch('actionA').then(() => {
// ...
})
使用
methods: {
...mapActions([
"increaseAsync" // this.increment() 等价 this.$store.commit('increment')
])
},
Module
分割成多个模块
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 的状态
store.state.b // -> moduleB 的状态
action,局部状态通过
context.state
暴露出来,根节点状态则为context.rootState
const moduleA = { // ... actions: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit('increment') } } } }
命名空间
export const moduleA={
namespaced: true,
state:()=>({
numA:1
}),
mutations:{// 方法
login(state) {
state.numA++
}
},
getters: { // 类似计算属性
doneNum(state) {
return state.numA + 1
}
}
}
=========
<button @click="add">Click</button>
{{sex}}
=========
computed: {
...mapState({
num:state => state.a.numA
}),
...mapGetters({
sex: 'a/doneNum'
})
}
methods: {
...mapMutations({
add:'a/login'
})
}
传参
mutations:{
login(state,str) {
console.log(str);
state.numA++
}
}
<button @click="add(10)">Click</button>
Actions 同理跟mutaion 类似
也可以这种形式
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo', // -> this.foo()
'bar' // -> this.bar()
])
使用辅助函数查找命名空间
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('a')
export default {
computed: {
// 在 `some/nested/module` 中查找
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
// 在 `some/nested/module` 中查找
...mapActions([
'foo',
'bar'
])
}
}
总结
state 数据
getters 计算属性
mutaions 同步方法
actions 异步方法
modules 分模块
表单处理
双向绑定的计算属性
<input v-model="message">
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}
模块重用
这个状态对象会通过引用被共享,导致状态对象被修改时 store 或模块间数据互相污染的问题。
实际上这和 Vue 组件内的 data
是同样的问题。因此解决办法也是相同的——使用一个函数来声明模块状态
const MyReusableModule = {
state: () => ({
foo: 'bar'
}),
// mutation, action 和 getter 等等...
}
watch
页面上
watch: {
'$store.state.app.language': function () {
//你需要执行的代码
}
}
监控state,getter的数据的变化
watch<T>(
getter: (state: S, getters: any) => T,
cb: (value: T, oldValue: T) => void,
options?: WatchOptions): () => void;
mounted() {
this.unsub = this.$store.watch(
// return 返回的监听的值,返回的也可以是数组
(state,getters)=>{
return state.a.numA
},
//现在的值,之前的值
(value,oldValue)=>{
console.log(value,oldValue);
} ,
// 是否深度监控
{
deep:true
}
);
},
destroyed() {
this.unsub();
},
subscribe
发布订阅的统一监控
created() {
this.unsubscribe = this.$store.subscribe((mutation, state) => {
if (mutation.type === 'updateStatus') {
console.log(`Updating to ${state.status}`);
// Do whatever makes sense now
if (state.status === 'success') {
this.complex = {
deep: 'some deep object',
};
}
}
});
},
beforeDestroy() {
this.unsubscribe();
},
记得离开的时候要取消订阅
vuex-persistedstate
在页面重新加载之间坚持并重新补充Vuex状态。
https://github.com/robinvdvleuten/vuex-persistedstate#readme
其实底层就是默认把state
存在localStorage
import Vuex from "vuex";
import createPersistedState from "vuex-persistedstate";
const store = new Vuex.Store({
// ...
plugins: [createPersistedState()],
});
在需要的模块里面添加,直接传给后台,如果清理的话直接改state
里面的值就行了
import createPersistedState from 'vuex-persistedstate';
import Cookies from 'js-cookie';
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
plugins: [createPersistedState({
storage: {
getItem: key => Cookies.get(key),
setItem: (key, value) => Cookies.set(key, value, { expires: 3, secure: true }),
removeItem: key => Cookies.remove(key)
}
})],
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
});
决定自己的高度的是你的态度,而不是你的才能
记得我们是终身初学者和学习者
总有一天我也能成为大佬