vue3学习—state的变化和使用


最近公司项目需要使用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,
    };
  },
};

博主开始运营自己的公众号啦,感兴趣的可以关注“飞羽逐星”微信公众号哦,拿起手机就能阅读感兴趣的博客啦!

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞羽逐星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值