百科狗-知识改变命运!
--

状态管理 - pinia - vue 规模化

梵高1年前 (2023-11-21)阅读数 21#技术干货
文章标签状态

状态管理

从技术上讲,每一个 Vue 组件实例都已经在“管理”它自己的响应式状态了。我们以一个简单的计数器组件为例:

{{ count }}

它是一个独立的单元,由以下几个部分组成:

  • 状态(state):驱动整个应用的数据源;
  • 视图(view):对状态的一种声明式映射;
  • 动作(active):状态根据用户在视图中的输入而作出相应变更的可能方式。

下面是“单向数据流”这一概念的简单图示:


然而,当我们有多个组件共享一个共同的状态时,就没有这么简单了:

  • 多个视图可能都依赖于同一部分状态。
  • 不同视图中的动作可能需要更改同一部分状态。

对于情景 1,一个可行的办法是将共享状态“提升”到共同的祖先组件上去,再通过props传递下来。然而在深层次的组件树结构中这么做的话,很快就会使得代码变得繁琐冗长。这会导致另一个问题:props深潜。

对于情景 2,我们经常发现自己会直接通过模板引用获取父/子实例,或者通过触发的事件尝试改变和同步多个状态的副本。但这些模式的健壮性都较为脆弱,并且很快就会导致不可维护的代码。

一个更简单直接的解决方案是抽取出组件间的共享状态,放在一个全局单例中来管理。这样我们的组件树就变成了一个大的“视图”,而任何位置上的组件都可以访问其中的状态或触发动作。


用响应性 API 做简单状态管理

如果你有一部分状态需要在多个组件实例间共享,你可以使用reactive()来创建一个响应式对象,并在不同组件中导入它:

// store.js
import { reactive } from 'vue'

export const store = reactive({
  count: 0
})
From A: {{ store.count }}
From B: {{ store.count }}

现在每当 store 对象被更改时,都会自动更新它们的视图。现在我们有了单一的数据源。

然而,这也意味着任意一个导入了 store 的组件都可以随意修改它的状态:

 From B: {{ store.count }} 

虽然这在简单的情况下是可行的,但从长远来看,可以被任何组件任意改变的全局状态是不太容易维护的。为了确保改变状态的逻辑像状态本身一样集中,建议在 store 上定义方法,方法的名称应该要能表达出行动的意图:

// store.js
import { reactive } from 'vue'

export const store = reactive({
  count: 0,
  increment() {
    this.count++
  }
})
 From B: {{ store.count }} 


请注意这里点击的处理函数使用了store.increment(),带上了圆括号作为内联表达式调用,因为它并不是组件的方法,并且必须要以正确的this上下文来调用。


除了我们这里用到的单个响应式对象作为一个store之外,你还可以使用其他响应性 API 例如ref()或是computed(),或是甚至通过一个可组合函数来返回一个全局状态:

import { ref } from 'vue'

// 全局状态,创建在模块作用域下
const globalCount = ref(1)

export function useCount() {
  // 局部状态,每个组件都会创建
  const localCount = ref(1)

  return {
    globalCount,
    localCount
  }
}

事实上,Vue 的响应性系统与组件层是解耦的,这使得它非常灵活。



SSR 考量

如果你正在构建一个需要利用服务端渲染(SSR)的应用程序,由于store是跨多个请求共享的单例,上述模式可能会导致问题。这在 SSR 指引那一章节会讨论更多细节。

状态管理 - pinia - vue 规模化


Pinia

虽然我们的手动状态管理解决方案在简单的场景中已经足够了,但是在大规模的生产应用中还有很多其他事项需要考虑:

  • 更强的团队协作约定。
  • 与 Vue DevTools 集成,包括时间轴、组件内部审查和时间旅行调试。
  • 模块热更新(HMR)。
  • 服务端渲染支持。

Pinia就是一个实现了上述需求的状态管理库,由 Vue 核心团队维护,对 Vue 2 和 Vue 3 都可用。

现有用户可能对Vuex更熟悉,它是 Vue 之前的官方状态管理库。由于 Pinia 在生态系统中能够承担相同的职责且能做得更好,因此 Vuex 现在处于维护模式。它仍然可以工作,但不再接受新的功能。对于新的应用程序,建议使用 Pinia。

事实上,Pinia 这款产品最初是为了探索 Vuex 的下一个版本,整合了核心团队关于 Vuex 5 的许多想法。最终,我们意识到 Pinia 已经实现了我们想要在 Vuex 5 中提供的大部分内容,因此决定将其作为新的官方推荐。

相比于 Vuex,Pinia 提供了更简洁直接的 API,并提供了组合式风格的 API,最重要的是,在使用 TypeScript 时它提供了非常好的类型推导。

鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com

免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)