复杂交互的项目使用vuex如何更好地组织代码

30,953 阅读4分钟

这是我参与8月更文挑战的第24天,活动详情查看:8月更文挑战

阅读之前希望你有vuex的基础知识以及拥有一定的项目经验。

最近一年左右做一个视频在线编辑的项目,该项目是基于vue2.x的。项目中最复杂的页面是编辑页面,页面大概长这样(找了个类似的界面):

image.png

可以看到界面比较复杂,大大小小组件差不多几十个,如果不使用状态管理库的话,使用父子组件交互比较麻烦,所以最终选用了vuex作为状态管理的库。

那么像这种比较复杂的项目,vuex的代码将如何组织呢?下面是我推荐的方法:

首先一个项目会有很多模块(或者叫页面),我的建议是将store按照业务逻辑的模块进行划分,一个业务模块对应一个module

这里需要注意的是:

  1. 不要把所有的业务模块放到一个store里面,这样项目状态变多之后就不太好维护。
  2. 一个业务模块不要对应多个vuex的module,即使很复杂。

犯下的错(可以跳过)

这两个坑我都踩过,刚开始做项目的时候,项目比较小,也很简单,编辑页面也没有现在那么复杂,我大概看了一下,需要存的状态只有用户信息和编辑页面的一些状态,没多少,我就放一起了。代码大概这样,所有的状态都在store中

export const store = new Vuex.Store({
    state: {
        userInfo:{
            id:'',
            token:'',
            phone:''
        },
        materials:[],
        audio:[],
        task:[]
    },
    mutations: {},
    modules: {},
})

这样搞完之后,代码稳定运行了一段时间。 后来产品让加功能,支持多个视频场景,支持背景,支持滤镜,分辨率调整,素材动画等等乱七八糟的功能,需要存的状态也多了很多,都放到一起,store这个文件就太长了,达到了一千多行。在这种情况下,我感觉状态再加下去store那个文件会越来越不好维护,所以重构了下代码,这时我犯下了第二个错误:

我把编辑页面的状态分成了好几个module,大概长这样

const user={
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}
const material = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const audio = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}
//...其他模块

const store = new Vuex.Store({
  modules: {
    user:user,
    material: material,
    audio: audio,
    //其他模块
  }
})

这样带来的问题是,代码太分散了,我一个编辑页面就对应了好几个module,太分散了维护也不好维护,也不够模块化。

最终结局方案

最终解决方案就是:一个单独的业务模块对应一个store的模块

我项目中涉及的业务模块有:用户模块,编辑模块,管理模块,工具包模块,假如每个模块都有需要存储的状态,就可以搞4个module

const store = new Vuex.Store({
  modules: {
    user,
    edit,
    manage,
    toolkit
  }
})

每个模块对应一个文件或者文件夹,有的模块状态比较简单,例如user,新建一个user.js文件存放状态即可,对于复杂的模块,例如edit,就需要建立一个文件夹了。

目录如下:

vuex-demo/store
├── index.js
└── module
    ├── edit
    │   ├── audio.js
    │   ├── component.js
    │   ├── edit-mutations.js
    │   ├── edit.js
    │   └── material.js
    └── user.js

搞成一个文件夹(而不是一个文件)是为了不把所有的状态都写在edit.js中,防止一个文件过大。在edit.js中使用拓展运算法又做了进一步的代码模块化,代码如下:

edit.js代码如下:

import { audio } from './audio'
import {material} from './material'

export const edit = {
    state: () => ({
        ...audio.state,
        ...material.state
    }),
    getters: {
        ...audio.getters,
        ...material.getters
    },
    mutations: {
        ...audio.mutation,
        ...material.mutation
    },
    actions: {
        ...audio.actions,
        ...material.actions
    },
}

就这样,很简单哈。

说了那么多,大部分都是废话,有用的代码不过十几行,代码放在这里了传送门

vuex持久化插件推荐

我们存在vuex中的数据,尤其是用户数据,一刷新页面就无了,这和我们的预期不一样,好多人(尤其是年轻人)以为的状态管理库是可以持久保存的,即我刷新页面也还在。

之所以这样以为其实是对vuex的本质认知不够,vuex的本质就是一个JS大对象,保存在内存里,类似于下面

let store={state:{},getter:{}}

new Vue({  store: store})

你一刷新页面,内存中的数据肯定清空,所以store中的数据无了也是正常的。如果你要存起来,你可以选择vuex和localStorage或者sessionStorage或者cookie配合。 你需要

  1. 提交Mutation时,同时存到本地储存中(注意如果是对象的话需要JSON.stringify)
  2. 刷新页面时(可以在App.vue中的created方法中),从本地储存中取到用户信息,如果有的话提交一下Mutation
export const user = {
    state: () => ({
       info:{}
    }),
    getters: {},
    mutation: {
        setUser(state,info){//1. 提交Mutation时,同时存到本地储存中
            localStorage.setItem('user',JSON.stringify(info))
            state.info=info
        }
    },
    actions: {},
}


    created() {
        const userInfo=localStorage.getItem('user')
        if(userInfo){
            // 提交Mutation,更新用户信息
        }
    }

这样存,你有一个数据你就存一次,有两个数据就存两次,有n个就存n次,太累了,所以推荐个插件, 在提交mutation时自动存,页面刷新时自动更新,方便的很。就不写demo了,累了。

插件地址 vuex-persistedstate

这一篇终于水完了,明天不知道写什么了,希望大家给点建议,评论区留言一下。

🐢