高品质的网站开发公司,网站策划与维护,开源免费cms可商业用,网站建设高端培训1.什么是状态管理
在开发中#xff0c;我们会的应用程序需要处理各种各样的数据#xff0c;这些数据需要保存在我们应用程序的某个位置#xff0c;对于这些数据的管理我们就称之为状态管理。
在之前我们如何管理自己的状态呢#xff1f;
在Vue开发中#xff0c;我们使用…1.什么是状态管理
在开发中我们会的应用程序需要处理各种各样的数据这些数据需要保存在我们应用程序的某个位置对于这些数据的管理我们就称之为状态管理。
在之前我们如何管理自己的状态呢
在Vue开发中我们使用组件化的开发方式在组件中我们定义data或者在setup中返回使用的数据这些数据我们称之为state在模块template中我们可以使用这些数据模块最终会被渲染成DOM我们称之为View在模块中我们会产生一些行为事件处理这些行为事件时有可能会修改state这些行为我们称之为actions
2.Vuex的状态管理
管理不断变化的state本身也是非常困难的
状态之间相互会存在依赖一个状态的变化会引起另一个状态的变化View页面也有可能引起状态的变化当应用程序复杂时state在什么时候因为什么原因发生了变化发生了怎么样的变化会变得非常难以控制和追踪 因此我们是否可以考虑将组件的内部状态抽离出来以一个全局单例的方式来管理呢在这种模式下我们的组件树构成了一个巨大的 “试图View”不管在树的那个位置任何组件都能获取状态或者触发行为通过定义和隔离状态管理中的各个概念并通过强制性的规则来维护视图和状态间的独立性我们的代码便会变得更加结构化和易于维护跟踪 这就是Vuex背后的基本思想它借鉴了FluxReduxElm纯函数语言redux有借鉴它的思想
当然目前Vue官网也在推荐使用Pinia进行状态管理我后续也会进行学习。
3.Vuex的状态管理 4.Vuex的安装
npm install vuex5.Vuex的使用
在src目录下新建store目录store目录下新建index.js,内容如下
import { createStore } from vuex;const store createStore({state:() ({counter:100})
})export default store在main.js中引用
import { createApp } from vue
import App from ./App.vue
import store from ./storecreateApp(App).use(store).mount(#app)App.vue中使用
templatediv classapph2App当前计数{{ $store.state.counter }}/h2HomeCom/HomeCom /div
/templatescript setupimport HomeCom from ./views/HomeCom.vue
/scriptstyle
/style
6.创建Store
每一个Vuex应用的核心就是store仓库
store本质上是一个容器它包含着你的应用中大部分的状态state); Vuex和单纯的全局对象有什么区别呢
Vuex的状态存储是响应式的
当Vue组件从store中读取状态的时候若store中的状态发生变化那么相应的组件也会被更新
你不能直接改变store中的状态
改变store中的状态的唯一途径就是显示提交commitmutation这样使得我们可以方便的跟踪每一个状态的变化从而让我们能够通过一些工具帮助我们更好的管理应用的状态
使用步骤
创建Store对象在app中通过插件安装
HomeCom.vue
templatedivh2Home当前计数{{ $store.state.counter }}/h2button clickincrement1/button/div
/templatescript setupimport { useStore } from vuex;const store useStore()function increment(){// store.state.counterstore.commit(increment)}
/scriptstyle scoped/stylestore/index.js
import { createStore } from vuex;const store createStore({state:() ({counter:100}),mutations:{increment(state){state.counter}}
})export default store7.在computed中使用Vuex
options-api
h2Computed当前计数{{ storeCounter }}/h2scriptexport default{computed:{storeCounter(){return this.$store.state.counter}}}
/scriptComponsition-API h2Componsition-API中Computed当前计数{{ counter }}/h2const store useStore()// const setupCounter store.state.counter; // 不是响应式const { counter } toRefs(store.state);8.mapState函数
options-api中使用 !-- 普通使用 --divname:{{ $store.state.name }}/divdivlevel:{{ $store.state.level }}/div!-- mapState数组方式 --divname:{{ name }}/divdivlevel:{{ level }}/div!-- mapState对象方式 --divname:{{ sName }}/divdivlevel:{{ sLevel }}/divscriptimport { mapState } from vuex;export default {computed:{fullname(){return xxx},...mapState([name,level]),...mapState({sName:state state.name,sLevel:state state.level})}}
/scriptComponsition-API !-- Setup中 mapState对象方式 --!-- divname:{{ cName }}/divdivlevel:{{ cLevel }}/div --!-- Setup中 使用useState --divname:{{ name }}/divdivlevel:{{ level }}/divbutton clickincrementLevel修改level/buttonscript setup// import { computed } from vue;// import { mapState,useStore } from vuex;import { useStore } from vuex;
// import useState from ../hooks/useState
import { toRefs } from vue;// 1.一步步完成// const { name,level } mapState([name,level])// const store useStore()// const cName computed(name.bind({ $store:store }))// const cLevel computed(level.bind({ $store:store }))// 2. 使用useState// const { name,level } useState([name,level])// 3.直接对store.state进行结构(推荐)const store useStore()const { name,level } toRefs(store.state)function incrementLevel(){store.state.level}
/scripthooks/useState.js
import { computed } from vue;
import { useStore,mapState } from vuex;export default function useState(mapper){const store useStore()const stateFnsObj mapState(mapper)const newState {}Object.keys(stateFnsObj).forEach(key{newState[key] computed(stateFnsObj[key].bind({$store:store}))})return newState
}9.getters的基本使用
某些属性可能需要经过变化后来使用这个时候可以使用getters
import { createStore } from vuex;const store createStore({state:() ({counter:100,name:why,level:10,users:[{id:111,name:why,age:20},{id:112,name:kobe,age:30},{id:113,name:james,age:25},]}),mutations:{increment(state){state.counter}},getters:{doubleCounter(state){return state.counter * 2},totalAge(state){return state.users.reduce((preValue,item){return preValue item.age},0)},message(state){return name:${state.name} level:${state.level}}}
})export default store获取
templatedivbutton clickincrementLevel修改level/buttonh2doubleCounter:{{ $store.getters.doubleCounter }}/h2h2usertotalAge:{{ $store.getters.totalAge }}/h2h2message:{{ $store.getters.message }}/h2/div
/templatescriptexport default {}
/script
script setup/scriptstyle scoped/style注意getter是可以返回函数的 // 获取某一个frends是可以返回函数的getFriendById(state){return (id) {const friend state.friends.find(itemitem.id id)return friend;}}使用
h2friend-111:{{ $store.getters.getFriendById(111) }}/h2mapGetters的辅助函数
我们可以使用mapGetters的辅助函数 options api用法
scriptimport { mapGetters } from vuex;export default { computed:{// 数组语法// ...mapGetters([doubleCounter,totalAge,message]),// 对象语法...mapGetters({doubleCounter:doubleCounter,totalAge:totalAge,message:message}),...mapGetters([getFriendById])}}
/script**Composition-API中使用mapGetters **
script setupimport { toRefs } from vue;// computedimport { useStore } from vuex;// mapGettersconst store useStore();// 方式一
// const { message:messageFn } mapGetters([message])
// const message computed(messageFn.bind({ $store:store }))
// 方式二
const { message } toRefs(store.getters)
function changeAge(){store.state.name coder why
}
// 3.针对某一个getters属性使用computed
const message computed(() store.getters.message)
function changeAge(){store.state.name coder why
}
/script10. Mutation基本使用
更改Vuex的store中的状态的唯一方法是提交mutation:
mutations:{increment(state){state.counter},decrement(state){state.counter--}
}使用示例 store/index.js
import { createStore } from vuex;const store createStore({state:() ({counter:100,name:why,level:10,users:[{id:111,name:why,age:20},{id:112,name:kobe,age:30},{id:113,name:james,age:25},],friends:[{id:111,name:why,age:20},{id:112,name:kobe,age:30},{id:113,name:james,age:25},]}),getters:{doubleCounter(state){return state.counter * 2},totalAge(state){return state.users.reduce((preValue,item){return preValue item.age},0)},message(state){return name:${state.name} level:${state.level}},// 获取某一个frends是可以返回函数的getFriendById(state){return (id) {const friend state.friends.find(itemitem.id id)return friend;}}},mutations: {increment(state){state.counter},changeName(state){state.name 王小波},changeLevel(state){state.level},changeInfo(state,userInfo){state.name userInfo.name;state.level userInfo.level}},
})export default storetemplatedivbutton clickchangeName修改name/buttonh2Store Name:{{ $store.state.name }}/h2button clickchangeLevel修改level/buttonh2Store Level:{{ $store.state.level }}/h2button clickchangeInfo修改level和name/button/div
/templatescriptexport default {methods:{changeName(){console.log(changeName)// // 不符合规范// this.$store.state.name 李银河this.$store.commit(changeName)},changeLevel(){this.$store.commit(changeLevel)},changeInfo(){this.$store.commit(changeInfo,{name:张三,level:100});}}}
/scriptstyle scoped/style Mutation常量类型 1.定义常量 store/mutation-type.js
export const CHANGE_INFO CHANGE_INFO2.定义mutation 引入 store/index.js
import { CHANGE_INFO } from ./mutation_types;[CHANGE_INFO](state,userInfo){state.name userInfo.name;state.level userInfo.level}3.提交mutation 引入 HomeCom.vue
import {CHANGE_INFO } from /store/mutation_typeschangeInfo(){this.$store.commit(CHANGE_INFO,{name:张三,level:100});}10.mapMutations的使用
在options-api中
templatedivbutton clickchangeName修改name/buttonh2Store Name:{{ $store.state.name }}/h2button clickchangeLevel修改level/buttonh2Store Level:{{ $store.state.level }}/h2button clickchangeInfo({name:张三,level:1999})修改level和name/button/div
/template scriptimport { mapMutations } from vuex;import {CHANGE_INFO } from /store/mutation_typesexport default {computed:{},methods:{btnClick(){console.log(btnClick)},...mapMutations([changeName,changeLevel,CHANGE_INFO])}}
/script style scoped/stylecomposition-api中
templatedivbutton clickchangeName修改name/buttonh2Store Name:{{ $store.state.name }}/h2button clickchangeLevel修改level/buttonh2Store Level:{{ $store.state.level }}/h2button clickchangeInfo({name:张三,level:1999})修改level和name/button/div
/template script setupimport { mapMutations,useStore } from vuex;import { CHANGE_INFO } from /store/mutation_typesconst store useStore();// 1.手动映射和绑定const mutations mapMutations([changeName,changeLevel,CHANGE_INFO])const newMutations {}Object.keys(mutations).forEach(key {newMutations[key] mutations[key].bind({$store:store})}) const { changeName,changeLevel,changeInfo } newMutations
/scriptstyle scoped/stylemutation重要原则 1.一条重要的原则就是要记住mutation必须是同步函数
这是因为devtool工具会记录mutation的日记每一条mutation被记录devtools都需要捕捉到前一状态和后一状态的快照但是在mutation中执行异步操作就无法追踪到数据的变化
11. Actions的基本使用
templatedivh2当前计数{{ $store.state.counter }}/h2button clickactionBtnClick发起action/buttonh2当前计数{{ $store.state.name }}/h2button clickactionchangeName发起action修改name/button/div
/template scriptexport default {computed:{},methods:{actionBtnClick(){this.$store.dispatch(incrementAction)},actionchangeName(){this.$store.dispatch(changeNameAction,bbb)}}}
/script
script setup/scriptstyle scoped/stylemapActions的使用
componets-api和options-api的使用
templatedivh2当前计数{{ $store.state.counter }}/h2button clickincrementAction发起action/buttonh2当前计数{{ $store.state.name }}/h2button clickchangeNameAction(bbbccc)发起action修改name/buttonbutton clickincrementincrement按钮/button/div
/template !-- scriptimport { mapActions } from vuex;export default {computed:{},methods:{...mapActions([incrementAction,changeNameAction])}}
/script --
script setupimport { useStore,mapActions } from vuex;const store useStore();const actions mapActions([incrementAction,changeNameAction]);const newActions {}Object.keys(actions).forEach(key {newActions[key] actions[key].bind({$store:store})})const {incrementAction,changeNameAction} newActions;// 2.使用默认的做法// import { useStore } from vuex;// const store useStore();// function increment(){// store.dispatch(incrementAction)// }
/scriptstyle scoped/style** actions发起网络请求**
store/index.js文件
import { createStore } from vuex;
import { CHANGE_INFO } from ./mutation_types;
const store createStore({state:() ({counter:100,name:why,level:10,users:[{id:111,name:why,age:20},{id:112,name:kobe,age:30},{id:113,name:james,age:25},],friends:[{id:111,name:why,age:20},{id:112,name:kobe,age:30},{id:113,name:james,age:25},],// // 服务器数据banners:[],recommends:[]}),getters:{doubleCounter(state){return state.counter * 2},totalAge(state){return state.users.reduce((preValue,item){return preValue item.age},0)},message(state){return name:${state.name} level:${state.level}},// 获取某一个frends是可以返回函数的getFriendById(state){return (id) {const friend state.friends.find(itemitem.id id)return friend;}}},mutations: {increment(state){state.counter},changeName(state){state.name 王小波},changename(state,name){state.name name},changeLevel(state){state.level},// changeInfo(state,userInfo){// state.name userInfo.name;// state.level userInfo.level// } [CHANGE_INFO](state,userInfo){state.name userInfo.name;state.level userInfo.level},changeBanners(state,banners){state.banners banners},changeRecommends(state,recommends){state.recommends recommends}},actions:{incrementAction(context){// console.log(context.commit) // 用于提交mutation// console.log(context.getters) // getters// console.log(context.state) // statecontext.commit(increment)},changeNameAction(context,payload){context.commit(changename,payload)},async fetchHomeMultidataAction(context){// // 1.返回promise给promise设置then// // fetch(http://123.207.32.32:8000/home/multidata).then(res{// // return res.json().then(data{// // console.log(data)// // })// // })// // 2.promisel链式调用 // // fetch(http://123.207.32.32:8000/home/multidata).then(res{// // return res.json()// // }).then(data {// // console.log(data)// // })// 3.await/async const res await fetch(http://123.207.32.32:8000/home/multidata)const data await res.json();console.log(data);// 修改state数据context.commit(changeBanners,data.data.banner.list)context.commit(changeRecommends,data.data.recommend.list)return aaaa;// // return new Promise(async (resolve,reject){// // const res await fetch(http://123.207.32.32:8000/home/multidata)// // const data await res.json();// // console.log(data);// // // 修改state数据// // context.commit(changeBanners,data.data.banner.list)// // context.commit(changeRecommends,data.data.recommend.list)// // // reject()// // resolve(aaaa)// // })// }}
})export default storeHomeCom.vue
templatedivh2Home Page/h2ultemplate v-foritem in $store.state.home.banners :keyitem.acmli{{ item.title }}/li/template/ul/div
/template script setupimport { useStore } from vuex;// 进行vuex网络请求const store useStore()store.dispatch(fetchHomeMultidataAction).then(res{console.log(home中的then被回调:,res)})
/scriptstyle scoped/stylemodule的基本使用
store/index.js文件
import { createStore } from vuex;
import { CHANGE_INFO } from ./mutation_types;
import homeModule from ./modules/home
const store createStore({state:() ({counter:100,name:why,level:10,users:[{id:111,name:why,age:20},{id:112,name:kobe,age:30},{id:113,name:james,age:25},],friends:[{id:111,name:why,age:20},{id:112,name:kobe,age:30},{id:113,name:james,age:25},],// // 服务器数据// banners:[],// recommends:[]}),getters:{doubleCounter(state){return state.counter * 2},totalAge(state){return state.users.reduce((preValue,item){return preValue item.age},0)},message(state){return name:${state.name} level:${state.level}},// 获取某一个frends是可以返回函数的getFriendById(state){return (id) {const friend state.friends.find(itemitem.id id)return friend;}}},mutations: {increment(state){state.counter},changeName(state){state.name 王小波},changename(state,name){state.name name},changeLevel(state){state.level},// changeInfo(state,userInfo){// state.name userInfo.name;// state.level userInfo.level// } [CHANGE_INFO](state,userInfo){state.name userInfo.name;state.level userInfo.level},// changeBanners(state,banners){// state.banners banners// },// changeRecommends(state,recommends){// state.recommends recommends// }},actions:{incrementAction(context){// console.log(context.commit) // 用于提交mutation// console.log(context.getters) // getters// console.log(context.state) // statecontext.commit(increment)},changeNameAction(context,payload){context.commit(changename,payload)},// async fetchHomeMultidataAction(context){// // 1.返回promise给promise设置then// // fetch(http://123.207.32.32:8000/home/multidata).then(res{// // return res.json().then(data{// // console.log(data)// // })// // })// // 2.promisel链式调用 // // fetch(http://123.207.32.32:8000/home/multidata).then(res{// // return res.json()// // }).then(data {// // console.log(data)// // })// // 3.await/async // const res await fetch(http://123.207.32.32:8000/home/multidata)// const data await res.json();// console.log(data);// // 修改state数据// context.commit(changeBanners,data.data.banner.list)// context.commit(changeRecommends,data.data.recommend.list)// return aaaa;// // return new Promise(async (resolve,reject){// // const res await fetch(http://123.207.32.32:8000/home/multidata)// // const data await res.json();// // console.log(data);// // // 修改state数据// // context.commit(changeBanners,data.data.banner.list)// // context.commit(changeRecommends,data.data.recommend.list)// // // reject()// // resolve(aaaa)// // })// }},modules:{home:homeModule}
})export default storemodules/home.js
export default{state:()({// 服务器数据banners:[],recommends:[]}),mutations:{changeBanners(state,banners){state.banners banners},changeRecommends(state,recommends){state.recommends recommends}},actions:{async fetchHomeMultidataAction(context){// 1.返回promise给promise设置then// fetch(http://123.207.32.32:8000/home/multidata).then(res{// return res.json().then(data{// console.log(data)// })// })// 2.promisel链式调用 // fetch(http://123.207.32.32:8000/home/multidata).then(res{// return res.json()// }).then(data {// console.log(data)// })// 3.await/async const res await fetch(http://123.207.32.32:8000/home/multidata)const data await res.json();console.log(data);// 修改state数据context.commit(changeBanners,data.data.banner.list)context.commit(changeRecommends,data.data.recommend.list)return aaaa;// return new Promise(async (resolve,reject){// const res await fetch(http://123.207.32.32:8000/home/multidata)// const data await res.json();// console.log(data);// // 修改state数据// context.commit(changeBanners,data.data.banner.list)// context.commit(changeRecommends,data.data.recommend.list)// // reject()// resolve(aaaa)// })}}
}HomeCom.vue
templatedivh2Home Page/h2ultemplate v-foritem in $store.state.home.banners :keyitem.acmli{{ item.title }}/li/template/ul/div
/template script setupimport { useStore } from vuex;// 进行vuex网络请求const store useStore()store.dispatch(fetchHomeMultidataAction).then(res{console.log(home中的then被回调:,res)})
/scriptstyle scoped/styleModules-默认模块化
Home.vue
templatedivh2Home Page/h2h2Counter模块的counter{{ $store.state.counter.count }}/h2h2Counter模块的doubleCounter{{ $store.getters.doubleCount }}/h2button clickincrementCountcount模块1/button/div
/template script setupimport { useStore } from vuex;// 进行vuex网络请求const store useStore()function incrementCount(){store.dispatch(incrementCountAction)}
/scriptstyle scoped/stylestore/index.js文件
const counter {namespaced:true,state:() ({count:99}),mutations:{incrementCount(state){state.count}},getters:{doubleCount(state,getters,rootState){return state.count rootState.rootCounter}},actions:{incrementCountAction(context){context.commit(incrementCount)}}
}export default counter修改模块子的值
HomeCom.vue
templatedivh2Home Page/h2h2Counter模块的counter{{ $store.state.counter.count }}/h2h2Counter模块的doubleCounter{{ $store.getters[counter/doubleCount] }}/h2button clickincrementCountcount模块1/button/div
/template script setupimport { useStore } from vuex;// 进行vuex网络请求const store useStore()function incrementCount(){store.dispatch(counter/incrementCountAction)}// module修改或派发根组件// 如果我们希望在action中修改root中的state那么有如下方式// changeNameAction({commit,dispatch,state,rootState,getters,rootGetters}){// commit(changeName,kobe);// commit(changeNameRootName,null,{root:true});// dispatch(changeRootNameAction,null,{root:true});// }
/scriptstyle scoped/style感谢观看我们下次见