1:创建store
import { cretaeStore } from "vuex"
import aModule from './a.js' // 其他的store
const changeInfo = 'changeInfo'
const store = createStore({
state:() => ({
counter: 0,
friends: [
{name: "haha", id: 1},
{name: "hehe", id: 2},
]
}),
mutations: {
increment(state, payload){ // 传递的参数会携带在payload中
state.counter += payload; // 修改对应的state
},
// 将方法抽离成常量,使用时需要用计算属性
[changeInfo](state, payload){}
},
getters: {
// getters: 可以调用其他的getters
doubleCount(state, getters) {
return state.count + getters.myCount + rootState.rootCounter
},
myCount(state){
return state.count; // 没啥用,举个例子而已
},
getFriendsById(state){
return function (id) {
return state.friends.find(item => item.id === id);
}
}
},
actions: {
// 异步函数自动返回promise
incrementAction(context, payload) {
return new Promise(async (resolve, reject) => {
const res = await fetch("http://xxx");
const data = await res.json();
context.commit("increment", data);
resolve("succ: ", data);
})
}
},
modules: {
a: aModule
}
})
export default store
2: 在main中导入并use store
Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中
- 在根组件中注入所有子组件:把 store 对象提供给 “store” 选项
// 官方通过new Vue创建
const app = new Vue({
el: '#app',
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
store,
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div>
`
})
// 通过createApp创建
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
// use store
createApp(App).use(store).mount('#app')
3: 在子组件中使用store
// 1模板中
$store.state.counter
// 2方法中 setup
import { useStore } from "vuex"
const store = useStore();
store.state.counter // 直接修改这个是可以成功的,但是不建议这么做
store.commit("increment") // 修改counter
// 如何简写store.state.counter => 使用toRefs
const {counter} = toRefs(store.state) // {{counter}} 保持响应式
// 3方法中 option
// 1. 通过computed 简写 store中的state属性,模板中直接 {{storeCounter}} 使用
computed: {
storeCounter() {
return this.$store.state.counter.count;
},
},
3.1 mapstate -- 映射函数
3方法中 optionApi 每个使用computed写一遍太繁琐了,所以有了这玩意
3.1.1 option Api中使用
import { mapState } from 'vuex';
// 1.模板中使用
{{ count }} --- {{ sCount }}
// 2.计算属性中混入
computed: {
...mapState(["count"]),
...mapState({ // 如果store中的属性和组件data中的属性重名了,重名的需要写成对象形式
sCount: state => state.count,
// ... 如果有其他的,则继续写
})
},
3.1.2 setup中使用
// 1.模板中使用
{{ sCount }}
// 2.mapState返回一个函数,使用copmuted执行这个函数,但是由于mapState底层用的是this.$store,而setup没有this,所以需要绑定useStore中的this
import {computed} from "vue";
import {mapState, useStore} from "vuex"
const {count} = mapState(["count"]); // return fn
const store = useStore();
const sCount = computed(count.bind({ $store: store }));
// 这种做法太繁琐,直接用toRefs + 解构完事了
4: getters
store 中定义“getter”(可以认为是 store 的计算属性)。
就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
// 模板中使用
{{ $store.getters.doubleCount }} --- {{ $store.getters.getFriendsById(1) }}
让 getter 返回一个函数的简写方式:
(在通过方法访问时,每次都会去进行调用,而不会缓存结果。)
4.1 mapGetters -- 映射函数
4.1.1 option api中使用
// 1. 模板中使用
{{ doubleCount}} ---- {{getFriendsById(1)}}
// 2. 映射
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(["doubleCount", "getFriendsById"]),
}
}
4.1.2 setup
// 1.模板中使用
{{ sDoubleCount }}
// 2. 映射
import {computed} from "vue";
import {mapGetters, useStore} from "vuex"
const { doubleCount } = mapGetters(["doubleCount"]); // return fn
const store = useStore();
const sDoubleCount = computed(doubleCount.bind({ $store: store }));
// 这种做法太繁琐,直接用toRefs + 解构完事了
// 3. 方法2:toRefs + 解构 => 包装成ref
const { doubleCount } = toRefs(store.getters)
// 4. 方法3:如果是争对某个getters属性使用computed
const doubuleCount = computed(() => store.getters.doubuleCount)
5: mutations
用于修改state 的数据
通过commit 派发
// 1模板中
$store.state.counter
// 2.方法中 setup
import { useStore } from "vuex"
const store = useStore();
store.commit("increment") // 修改counter
// 3.方法中 option
this.$store.commit("increment", payload)
5.1 mapMutations
5.1.1 option
// 使用
@click="increment(payload)"
// 映射
import { mapMutations } from 'vuex'
import { CHANGE_INFO } from "@/store/mutation_types"
export default {
methods: {
...mapMutations(["increment"])
}
}
5.1.2 compositon
// 使用
@click="increment(payload)"
// 映射
import { mapMutations, useStore } from 'vuex'
const store = useStore()
// 1.手动的映射和绑定
const mutations = mapMutations(["increment"])
const newMutations = {}
Object.keys(mutations).forEach(key => {
dnewMutations[key] = mutations[key].bind({ $store: store })
})
const { increment } = newMutations;
6: actions
通过dispatch 派发
// 模板显示
{{ $store.state.counter }}
// option api 派发action
this.$store.dispatch("incrementAction", payload);
// compositon api 派发action
const store = useStore();
function increment() {
store.dispatch("incrementAction",payload).then(res => {
// 可以在这里监听函数执行
clg(res);
})
}
6.1 mapActions
6.1.1 option
// 模板使用
@click="incrementAction(payload)"
// 映射
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions(["incrementAction"])
}
}
6.1.2 composition api
import { useStore, mapActions } from 'vuex'
const store = useStore()
// 1.在setup中使用mapActions辅助函数
const actions = mapActions(["incrementAction", "changeNameAction"])
const newActions = {}
Object.keys(actions).forEach(key => {
newActions[key] = actions[key].bind({ $store: store })
})
const { incrementAction, changeNameAction } = newActions
7: modules
在a.js中
默认情况下,action / mutation / getter 默认注册在全局命名空间 => 重名的方法会导致bug
export default {
namespaced: true, // 开启自己的命名空间
state: () => ({
// 服务器数据
banners: [],
}),
getters: {
aSdoubleCount(state, getters, rootState) {
return state.count + getters.myCount + rootState.counter
},
},
mutations: {},
actions: {
// context 中可以结构出六个参数
incrementCountAction({commit, dispatch, state, rootState, getters, rootGetters}){
// 修改根store中的数据
commit("increment", null, {root: true});
}
}
}
// 如果是a中的数据
// 使用时需要从模块中获取
{{ store.state.a.banners}}
// 除了state的数据,其他会被合并在一起
{{ $store.getters.aSdoubleCount}}
// 开启了命名空间后
{{ $store.getters["a/aSdoubleCount"]}}
store.dispatch("a/incrementCountAction")