前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue3实践总结-状态管理

Vue3实践总结-状态管理

作者头像
吴文周
发布2022-03-09 14:44:14
5250
发布2022-03-09 14:44:14
举报
文章被收录于专栏:吴文周的专栏吴文周的专栏

状态管理

简述

  • 多个组件,多个模块之间共享状态是最常见的开发述求,场景之多不胜枚举,例如全局用户状态,修改用户信息全局响应变化等等。

常见的解决方案

  • 简单方案基于事件监听机制利用回调传参,多处订阅实现数据的流转。例如官方推荐的mitt事件库。优势简单的数据事件通信是能满足的,劣势随着数据复杂性变动,回调写法的代码阅读性,整体使用体验下降,使用方式也非常简单,具体实现如下:
代码语言:javascript
复制
//定义组合api事件流
const $emitter = mitt()
/**
 * @name: useOnChange
 * @msg: 监听事件emit
 */
export function useOnChange<T extends Function>(fun: T) {
  $emitter.on(EventsEnum.CHANGE, itemMessage => {
    fun(itemMessage)
  })
}
/**
 * @name: useChange
 * @msg: 触发事件emit
 * @param {*}
 */
export function useChange(itemMessage: number) {
  $emitter.emit(EventsEnum.CHANGE, itemMessage)
}
代码语言:javascript
复制
// A组件中触发事件发送数据
export default defineComponent({
  name: 'A',
  setup() {
   //组件A中发送数据
   const handlerClick = (item)=>{
     //使用组合api发送数据
     useChange(1)
   }
  }
 })

// B组件中监听事件获取数据
export default defineComponent({
  name: 'B',
  setup() {
    //回调中获取数据
   useOnChange((mes)=>{
    console.log(mes)
   })
  }
 })
 
// C 组件中监听事件获取数据
export default defineComponent({
  name: 'C',
  setup() {
   //回调中获取数据
   useOnChange((mes)=>{
     console.log(mes)
   })
  }
 })
  • 基于vue3的响应式官方一些简单的实践
代码语言:javascript
复制
const store = {
  debug: true,

  state: Vue.reactive({
    message: 'Hello!'
  }),

  setMessageAction(newValue) {
    if (this.debug) {
      console.log('setMessageAction triggered with', newValue)
    }

    this.state.message = newValue
  },

  clearMessageAction() {
    if (this.debug) {
      console.log('clearMessageAction triggered')
    }

    this.state.message = ''
  }
}
代码语言:javascript
复制
const appA = Vue.createApp({
  data() {
    return {
      privateState: {},
      sharedState: store.state
    }
  },
  mounted() {
    store.setMessageAction('Goodbye!')
  }
}).mount('#app-a')

const appB = Vue.createApp({
  data() {
    return {
      privateState: {},
      sharedState: store.state
    }
  }
}).mount('#app-b')
  • 知名状态管理库Redux,Flux,Vuex,这些都是非常优秀的第三方库

为什么明明有vuex你还在折腾啥?

  • 先抛出一个问题大家用了element那么久,请问知道this.$message是怎么实现的吗?如果什么都不管,项目来了上去就是一套全家桶,做一个项目和做十个项目有什么区别?既然新的机会来了为什么自己写一下vue3的组件,vue3的状态管理?
  • 业务与场景在项目初期比较简单,没有记录变更、保存状态快照、历史回滚/时光旅行的诉求,那为什么不自己做一个状态管理呢?
  • 核心实现功能:状态修改单项数据流,状态改变全局数据响应,代码约定,思考一下怎么解决这三个问题?

实现思路

  • 单项数据流,Readonly
  • 状态改变数据响应,组合api和响应式
  • 代码约束 使用ts 进行接口约定

其他大神的一些实现

站在巨人的肩膀上

  • 基于一些大神是vue3封装reduer思路自己也去做了实现
  1. 基础实现
代码语言:javascript
复制
/*
 * @Description:Reducer
 * @version: 1.0.0
 * @Author: 吴文周
 * @Date: 2021-02-26 13:45:46
 * @LastEditors: 吴文周
 * @LastEditTime: 2021-03-02 14:52:33
 */
import { readonly, ref } from 'vue'
// 全局缓存
const map = new WeakMap()
export function useModel(hook: Function) {
  if (!map.get(hook)) {
    const ans = hook()
    map.set(hook, ans)
  }
  return map.get(hook)
}
export function useReducer(reducer: Function, initialState = {}) {
  const state = ref(initialState)
  const dispatch = <T>(action: T) => {
    state.value = reducer(action, state.value)
  }
  return {
    state: readonly(state),
    dispatch,
  }
}
export function useStore(reducer: Function, initialState?: any) {
  return useReducer(reducer, initialState)
}

2.实现小型reduer

代码语言:javascript
复制
 /*
 * @Description:xxx全局状态
 * @version: 1.0.0
 * @Author: 吴文周
 * @Date: 2021-02-26 13:53:09
 * @LastEditors: 吴文周
 * @LastEditTime: 2021-03-20 16:10:59
 */
import { Ref } from 'vue'
import { useModel, useReducer } from './reducer'
// 状态接口
export interface State {
   oo: string,
   xx: string,
   cc: string,
}
// 行为接口
export interface Action {
  type: 'changeOO' | 'changeXX' | 'changeCC'//指定action
  payload: State
}
// 组合函数使用是 状态接口
export type StateType = Readonly<Ref<State>>
// 使用实例接口
interface Redux {
  state: StateType
  // 这里不是注释,只是这样的语法mark当不识别,保证优雅性,实际使用时放开注释
  //dispatch: <T extends Action>(action: T) => void
}
// 状态变更
function reducer(action: Action, state: State) {
  switch (action.type) {
    case 'changeOO':
     state.oo = action.payload.oo
     break
    case 'changeXX':
     state.xx = action.payload.xx
     break
    case 'changeCC':
    state.cc = action.payload.cc
     break
  }
  return { ...state }
}
// 初始化状态
function useStore() {
  const initialState = {
    oo: 'oo',
    xx: 'xx',
    cc: 'cc',
  }
  return useReducer(reducer, initialState)
}
// 组合api 函数可以被任意组件 在任意地方调用
export function useXXXRedux() {
  const redux: Redux = useModel(useStore)
  return redux
}

3.调用实现,在任意组件内,或者任何组合api内部,在哪里调用都行

代码语言:javascript
复制

export default defineComponent({
  name: 'D',
  setup() {
   //回调中获取数据
    const { state:xxState,dispatch } = useXXXRedux()
   //监听state变化
    watch(xxState, state => {
    })
   //触发状态改变
   dispatch({type:"changeOO",{payload:{oo:"iii"}}})
 })

总结

  • 缺点: 记录变更、保存状态快照、历史回滚/时光旅行的诉求 这些是缺失的
  • 优点:整体代码是简单明了的,无侵入式
  • 熟练使用第三方库是一个开发者的基础素养
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021/03/21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简述
  • 常见的解决方案
  • 为什么明明有vuex你还在折腾啥?
  • 实现思路
  • 其他大神的一些实现
  • 站在巨人的肩膀上
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档