天天看点

Vue3实践总结-状态管理总结

状态管理

简述

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

常见的解决方案

  • 简单方案基于事件监听机制利用回调传参,多处订阅实现数据的流转。例如官方推荐的mitt事件库。优势简单的数据事件通信是能满足的,劣势随着数据复杂性变动,回调写法的代码阅读性,整体使用体验下降,使用方式也非常简单,具体实现如下:
//定义组合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)
}
           

复制

// 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的响应式官方一些简单的实践
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 = ''
  }
}
           

复制

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 进行接口约定

其他大神的一些实现

  • 利用provide
  • 还有一些基于reactive等等一些想法

站在巨人的肩膀上

  • 基于一些大神是vue3封装reduer思路自己也去做了实现
  1. 基础实现
/*
 * @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

/*
 * @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内部,在哪里调用都行

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

复制

总结

  • 缺点: 记录变更、保存状态快照、历史回滚/时光旅行的诉求 这些是缺失的
  • 优点:整体代码是简单明了的,无侵入式
  • 熟练使用第三方库是一个开发者的基础素养