欢迎光临
我们一直在努力

为什么 Vue3 需要重新设计状态管理?

Vue3 发布之后,整个开发模式发生了非常大的变化。

最明显的就是:

Composition API。

过去我们更多写的是:

  • data
  • methods
  • computed
  • watch

而现在:

更多写的是:

  • ref
  • reactive
  • computed
  • composables

整个项目开始朝着”函数化”发展。

例如以前:

export default {
data(){},
methods:{}
}

现在更多写成:

const count = ref(0)

function increment(){
count.value++
}

状态与逻辑可以自由组合。

Composable 之间也可以相互复用。

如果 Vuex 仍然保持原来的设计:

Action



Mutation



State

整个开发体验就会显得十分割裂。

Vue3 希望的是:

开发者面对状态时,尽量保持 JavaScript 本身的思维方式。

而不是额外学习一套复杂的数据流。

Pinia 正是在这样的背景下重新设计的。


Pinia 的设计理念

如果只用一句话概括 Pinia:

Store 本身就是一个普通的模块。

例如:

以前 Vuex:

修改状态:

dispatch()



Action



commit()



Mutation

Pinia:

直接:

store.user = data

没有:

Mutation。

没有:

Commit。

没有:

Dispatch。

很多第一次接触 Pinia 的开发者都会觉得:

是不是太简单了?

事实上。

这正是 Pinia 最大的设计理念。

减少框架本身的概念。

Vue3 已经有:

  • ref
  • reactive
  • computed

状态管理应该尽量保持一致。

而不是重新创造一套新的 API。


为什么取消 Mutation?

这是很多 Vue2 开发者最关心的问题。

Vuex 当初为什么一定要求:

Mutation

原因其实有两个。

第一:

Vue2 的响应式限制。

第二:

方便 DevTools 记录状态变化。

但是到了 Vue3:

Proxy 已经能够完整追踪状态。

开发工具同样能够知道:

什么时候修改了数据。

因此:

Mutation 存在的价值已经越来越低。

反而增加了:

大量重复代码。

例如:

修改用户名。

Vuex:

定义 type



Mutation



Action



commit



dispatch

Pinia:

store.user.name="Tom"

整个过程更加符合 JavaScript 本身的开发习惯。


为什么 Pinia 更适合 TypeScript?

这是很多企业最终迁移的重要原因。

Vuex 出现的时候。

TypeScript 还没有今天这么流行。

因此:

Vuex 很多 API 都不是围绕类型推导设计的。

例如:

Getter。

Mutation。

Action。

都需要写大量声明。

IDE 很难自动推导。

很多时候需要:

手写泛型。

而 Pinia 从第一天开始。

就是围绕 TypeScript 设计。

例如:

const userStore = useUserStore()

userStore.user

IDE 可以自动推导:

user 的完整类型。

甚至:

Action 的参数。

返回值。

Getter。

全部能够自动提示。

这意味着:

开发效率明显提高。

错误更容易提前发现。

对于大型团队来说。

这是非常大的优势。


Pinia 为什么代码更容易维护?

真正的大型项目。

Store 通常不会只有:

User

还会有:

Order

Product

Permission

Dashboard

System

Message

Setting

如果仍然按照 Vuex 的方式。

每个模块:

Action。

Mutation。

Getter。

都会越来越多。

几年之后。

整个 Store 会变得非常庞大。

而 Pinia 的设计更接近普通 JavaScript 模块。

例如:

stores
├── user.ts
├── order.ts
├── product.ts

每个 Store 都是独立文件。

维护成本明显降低。


Pinia 与 Composition API 的关系

很多开发者没有注意到。

Pinia 和 Composition API 的思想其实完全一致。

例如:

Composition API:

const count = ref(0)

Pinia:

const userStore = useUserStore()

都是:

普通变量。

普通函数。

没有额外概念。

因此:

学习成本非常低。

对于刚学习 Vue3 的开发者来说。

几乎没有额外负担。


大型项目如何组织 Store?

很多教程都会这样写:

src

stores

user.ts

order.ts

product.ts

项目小时没有问题。

但是:

如果一个项目:

有:

三十多个业务模块。

整个 stores 目录很快会变得混乱。

更推荐结合上一篇介绍的:

Feature First。

例如:

src

features

user
store.ts
api.ts
types.ts

order
store.ts
api.ts
components

product

这样:

业务。

接口。

Store。

类型。

全部放在一起。

整个模块更加完整。

以后迁移。

删除。

拆分。

都会更加方便。


Store 应该负责什么?

很多团队:

把 Store 当数据库。

什么数据都放进去。

这是非常典型的错误。

真正适合放 Store 的通常只有:

  • 当前登录用户
  • Token
  • 权限
  • 主题
  • 国际化
  • 系统配置

而:

例如:

搜索框内容。

弹窗是否打开。

分页页码。

这些:

完全属于页面状态。

推荐直接:

ref()

reactive()

即可。

Store 应该保存:

跨页面共享的数据。

而不是:

整个页面所有状态。


Pinia 常见误区

第一:Store 过于庞大

很多项目:

最终只有:

AppStore

几千行代码。

所有状态。

所有方法。

全部放进去。

维护非常困难。

正确做法:

按业务拆分。


第二:Store 负责请求接口

例如:

login()



axios



Toast



Router



Store

所有逻辑混在一起。

建议:

Component



Service



API



Store

Store 只负责:

状态。

不要负责:

页面。

网络。

UI。


第三:所有数据永久缓存

很多开发者:

接口请求一次。

全部放 Store。

几年之后:

Store:

几十 MB。

真正需要长期保存的数据其实很少。

例如:

订单详情。

搜索结果。

一般离开页面即可释放。

不要为了缓存而缓存。


企业项目最佳实践

结合目前越来越多团队的经验。

推荐采用下面这种结构:

src
├── app
├── assets
├── features
│ ├── auth
│ ├── user
│ ├── order
│ ├── product
│ └── dashboard
├── shared
│ ├── components
│ ├── composables
│ ├── utils
│ └── types
├── router
├── services
├── stores
└── main.ts

其中:

  • Feature 保存业务。
  • Shared 保存公共资源。
  • Store 保存全局状态。
  • Service 负责业务逻辑。
  • API 专门负责请求。

整个架构职责更加清晰。

对于多人协作和 AI 编程工具都更加友好。

赞(0)
未经允许不得转载:X记录空间 » 为什么 Vue3 需要重新设计状态管理?