sate的变化和使用
最近公司项目需要使用vue3,发现vue3中的state变化较大,就干脆系统的学习下。把笔记做好站位,后面随时更新吧。
vue2中的state之前做过笔记,不懂得可以翻阅 深入剖析vuex.
一、state的变化
本文部分借鉴自大佬的笔记.
vue3中state获取状态的方法有多种,如下图所示,那么我们先了解reactive是什么意思吧!
1、reactive
1.什么是reactive
reactive是Vue3中提供实现响应式数据的方法。
在Vue2中响应式数据是通过defineProperty来实现的。
而在Vue3响应式数据是通过ES6的Proxy(代理,不懂得翻我es6笔记)来实现的。
2.reactive注意点
reactive参数必须是对象(json/arr),当传递的是非对象时,页面不会发生响应,即页面会渲染,但是后面操作数据后页面是不会响应的。
如果给reactive传递了其他对象,默认情况下修改对象,界面不会自动更新,如果想更新,可以通过重新赋值的方式。
2、state的类型
这里定义一个简单地state状态,简单类型、对象和数组,比较有代表性的类型。
这里的类型指的不是 js 的基础类型,而是说vue3提供的ref和reactive。
因为 vuex 把 state 变成了 reactive 的形式,所以我们要先弄清楚这一点,然后才能更好的使用其带来的优势。
state: {
count: 0,
myObject: {
time: '现在的时间:'
},
myArray: [1,2,2,3,4]
},
// 整体获取,这里不是setup里面哦
const allStateManage = () => {
const store = Vuex.useStore()
// 看看state的类型
console.log('state:', store.state)
console.log('state.count:', store.state.count)
console.log('state.myObject:', store.state.myObject)
}
整个state就是reactive的,成员又是什么样子的呢?
- 如果成员是简单类型,那么还是简单类型,并没有变成ref的,
- 如果成员是引用类型,获取时会变成reactive的。
1.setup里面的vuex的使用方式
import { useStore } from 'vuex'
setup() {
const store = useStore()
}
2.封装获取state方式
看到上面这些读取方式,是不是一个头两个大;这也太复杂了吧,我到底应该用什么方式?
我们应该做一个独立的js文件,然后在里面根据公司的要求,或者事先的约定,依据业务需求、项目需求来确定采用哪种方式。
在js文件里面封装好之后,组件里直接调用就好,不用管其他。这样就好维护多了。
const map = () => {
const store = Vuex.useStore()
/**
* 获取count,
* 用computed实现相应
*/
const getCount = () => {
return Vue.computed(() => store.state.count)
}
/**
* 获取count,
** 用 ref 实现相应
*/
const getRefCount = () => {
return Vue.ref(store.state.count)
}
/**
* 获取对象
*/
const getObject = () => {
return store.state.myObject
}
/**
* 获取只读对象
*/
const getReadonlyObject = () => {
return Vue.readonly(store.state.myObject)
}
/**
* 获取数组
*/
const getArray = () => {
return store.state.myArray
}
/**
* 获取只读数组
*/
const getReadonlyArray = () => {
return Vue.readonly(store.state.myArray)
}
/**
* 查询数组
** id:要查询的数据
*/
const filterArray = (id) => {
return Vue.computed(() => store.getters.filterArray(id))
}
return {
getCount,
getRefCount,
getObject,
getReadonlyObject,
getArray,
getReadonlyArray,
filterArray
}
}
export default map
最后附一下setup的代码,vue3的composition的方式实在是太方便了
setup() { // 传说中的setup
const store = Vuex.useStore()
// 状态的控制事件
const setCount = () =>{
store.commit('setCount')
store.commit('setTime')
store.commit('setArray')
store._mutations.setCount[0] // 这是什么?
}
// 获取state
const { allState } = allStateManage()
// 直接获取成员
const { memberCount, memberObject } = stateMemberManage()
// 间接获取成员
const { refCount, comCount, readonlyObject } = indirectManage()
// 间接获取成员
const { addCount, getAddCount, comGetAddCount, filterArray, comFilterArray } = operationManage()
// 通过map 获取 count
// 可以使用别名
const {
getCount: mapGetCount
} = map()
const mapCount = mapGetCount()
return { // 返回给模板,否则模板访问不到。
// 直接获取state
allState,
// 直接获取成员
memberCount,memberObject,
// 间接获取
refCount, comCount,readonlyObject,
// 操作后获取
addCount,getAddCount,comGetAddCount,filterArray,comFilterArray,
// map
mapCount,
// 设置state
setCount
}
}
二、state使用
这里我们模拟一个登录模块来演示vue3中vuex的使用。
//store.js
export default {
namespaced: true,
state: {
user: null,
loading: false,
},
mutations: {
setUser(state, payload) {
state.user = payload;
},
setLoading(state, payload) {
state.loading = payload;
},
},
actions: {
async login({ commit }, { loginId, loginPwd }) {
commit("setLoading", true);
const user = await userServ.login(loginId, loginPwd);
commit("setUser", user);
commit("setLoading", false);
return user;
},
async loginOut({ commit }) {
commit("setLoading", true);
await userServ.loginOut();
commit("setUser", null);
commit("setLoading", false);
},
async whoAmI({ commit }) {
commit("setLoading", true);
const user = await userServ.whoAmI();
commit("setUser", user);
commit("setLoading", false);
},
},
};
//login
export default {
setup() {
const loginId = ref("");
const loginPwd = ref("");
const store = useStore();
const router = useRouter();
const handleSubmit = async () => {
const user = await store.dispatch("loginUser/login", {
loginId: loginId.value,
loginPwd: loginPwd.value,
});
if (user) {
router.push("/"); // 登录成功
} else {
alert("账号/密码错误");
}
};
return {
loginId,
loginPwd,
handleSubmit,
loading: computed(() => store.state.loginUser.loading),
};
},
};
//home.js
export default {
setup() {
const store = useStore();
const router = useRouter();
const handleLoginOut = async () => {
await store.dispatch("loginUser/loginOut");
router.push("/login");
};
return {
loading: computed(() => store.state.loginUser.loading),
user: computed(() => store.state.loginUser.user),
handleLoginOut,
};
},
};
1、state代替方案global state
使用reactivity api代替vux。
import { reactive, readonly } from "vue";
// 创建默认的全局单例响应式数据,仅供该模块内部使用
const state = reactive({ user: null, loading: false });
// 对外暴露的数据是只读的,不能直接修改
// 也可以进一步使用toRefs进行封装,从而避免解构或展开后响应式丢失
export const loginUserStore = readonly(state);
// 登录
export async function login(loginId, loginPwd) {
state.loading = true;
const user = await userServ.login(loginId, loginPwd);
state.user = user;
state.loading = false;
}
// 退出
export async function loginOut() {
state.loading = true;
await userServ.loginOut();
state.loading = false;
state.user = null;
}
// 恢复登录状态
export async function whoAmI() {
state.loading = true;
const user = await userServ.whoAmI();
state.loading = false;
state.user = user;
}
//login.js
import { login, loginUserStore } from "../store/store.js";
export default {
setup() {
const loginId = ref("");
const loginPwd = ref("");
const router = useRouter();
const handleSubmit = async () => {
await login(loginId.value, loginPwd.value);
if (loginUserStore.user) {
router.push("/");
} else {
alert("账号密码错误");
}
};
return {
handleSubmit,
loginId,
loginPwd,
loginUserStore,
};
},
};
//home
import { loginOut, loginUserStore } from "./store/store.js";
export default {
setup() {
const router = useRouter();
const handleLoginOut = async () => {
await loginOut();
router.push("/login");
};
return {
handleLoginOut,
loginUserStore,
};
},
};
博主开始运营自己的公众号啦,感兴趣的可以关注“飞羽逐星”微信公众号哦,拿起手机就能阅读感兴趣的博客啦!