Skip to content

Vuex 和 Pinia 实现原理,以及他们之间的区别

https://pinia.vuejs.org/zh/introduction.html

https://vuex.vuejs.org/zh/

Vuex 实现原理

Vuex 基于 Vue 的响应系统,利用单向数据流和事件驱动模型的理念,以一种集中和可预测的方式来管理和维护应用程序的状态。

Vuex 通过提供一个全局单例模式来管理状态,这意味着状态始终是单一来源的。它借鉴了 Redux 的实现方式,包括使用纯函数(mutations)来改变状态,使用 actions 来处理异步操作,并使用 getters 来计算派生状态。此外,Vuex 还利用了 Vue.js 的响应性系统,以便当状态改变时,相关的组件能够自动更新。

  • 状态(state):在 Vuex 中,状态对象是保存整个应用状态的 JavaScript 对象,Vuex 使用一个单一的状态树,即将所有的状态保存到一个共享的对象中。

  • Getter:Getter 可以用来从状态树中派生出一些状态,例如过滤列表、计算属性等。

  • Mutations:Mutation 是更改状态的唯一方法,并且必须是同步事务。

  • Actions:Action 类似于 Mutation,不同在于,Action 提交的是 Mutation,而不是直接变更状态,Action 可以包含任意异步操作。

  • Modules:Vuex 提供了模块化的解决方案,允许我们将 store 分割成模块,每个模块拥有自己的 state、mutation、action、getter。

Pinia 实现原理

Pinia 主要借鉴了 Vuex 的一些核心概念,但是简化了 API 并引入了一些新的概念和特性。

Pinia 的核心概念是"stores",每个 store 都是一个独立的状态容器。这使得开发者可以更灵活地组织他们的状态,而不是像 Vuex 那样必须将所有状态放在一个大的单一对象中。Pinia 也利用了 Vue.js 的响应性系统,但它更加依赖 Vue 3 的 Composition API,这使得状态管理代码更容易组织和理解。此外,Pinia 还包含一些其他有用的特性,如内置的开发工具支持和服务器端渲染(SSR)支持。

  • Stores:在 Pinia 中,不再有一个大的单一状态树,而是有多个小的独立的状态容器(也就是 Stores)。每个 Store 都有自己的状态(state)、动作(actions)和 getters。

  • Setup 方法:Pinia 引入了新的概念,如 setup 方法,这是基于 Vue3 的 Composition API 的。在这个 setup 方法中,我们可以定义 state、getters 和 actions。

Vuex 和 Pinia 的主要区别

  • API 设计:Vuex 使用一种更传统的 API 设计,需要开发者理解一些特定的概念,如 mutations、actions 和 getters。而 Pinia 的 API 则更简单,主要基于 Vue 3 的 Composition API。

  • 状态组织:在 Vuex 中,所有的状态都被组织在一个大的单一对象中。而在 Pinia 中,每个 store 都是一个独立的状态容器,这使得状态更容易组织和管理。

  • 类型安全:Pinia 有更好的 TypeScript 支持,因此如果你使用 TypeScript,Pinia 可能会更适合你。

  • 开发工具支持:虽然 Vuex 和 Pinia 都支持 Vue.js 开发工具,但 Pinia 提供了一些更多的内置功能。

  • 服务器端渲染支持:Pinia 对服务器端渲染(SSR)提供了内置支持。

  • 兼容性:Vuex 和 Pinia 都支持 Vue 2 和 Vue 3。

Vuex 代码示例 1

js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  },
  actions: {
    increment(context) {
      context.commit('increment');
    }
  }
});

在这个例子中,你可以看到我们创建了一个新的 Vuex store,有一个 state 属性(存储状态),一个 mutations 属性(用于修改状态),以及一个 actions 属性(用于处理异步操作)。

Pinia 代码示例 1

js
import {createPinia} from 'pinia';

export const useStore = createPinia();

export const useCounterStore = defineStore('counter', {
  state: () => ({count: 0}),
  actions: {
    increment() {
      this.count++;
    }
  }
});

在 Pinia 的例子中,我们创建了一个名为 counter 的 store,有一个 state 属性(存储状态),以及一个 actions 属性(可以是异步操作,并且可以直接修改状态)。

这两个例子展示了 Vuex 和 Pinia 在 API 设计上的区别。在 Vuex 中,你需要通过提交 mutations 来修改状态,而在 Pinia 中,你可以直接在 actions 中修改状态。

Vuex 代码示例 2

在这个更复杂的 Vuex 示例中,我们管理用户信息和文章数据:

javascript
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    user: {
      name: '',
      email: ''
    },
    posts: []
  },
  mutations: {
    SET_USER(state, user) {
      state.user = user;
    },
    SET_POSTS(state, posts) {
      state.posts = posts;
    }
  },
  actions: {
    fetchUser({commit}, user) {
      // fetch user from API...
      commit('SET_USER', user);
    },
    fetchPosts({commit}) {
      // fetch posts from API...
      commit('SET_POSTS', posts);
    }
  },
  getters: {
    user: (state) => state.user,
    posts: (state) => state.posts
  }
});

Pinia 代码示例 2

在这个更复杂的 Pinia 示例中,我们管理用户信息和文章数据,但是 Pinia 提供了一种更简洁和直接的方式来处理状态:

javascript
import {createPinia} from 'pinia';

export const useStore = createPinia();

// user store
export const useUserStore = defineStore('user', {
  state: () => ({
    name: '',
    email: ''
  }),
  actions: {
    async fetchUser(user) {
      // fetch user from API...
      this.name = user.name;
      this.email = user.email;
    }
  }
});

// posts store
export const usePostsStore = defineStore('posts', {
  state: () => ({
    posts: []
  }),
  actions: {
    async fetchPosts() {
      // fetch posts from API...
      this.posts = posts;
    }
  }
});

在这两个例子中,您可以看到,使用 Vuex 时,我们需要调用 commit 方法并触发一个 mutation 来改变状态。然而在 Pinia 中,我们可以在 action 中直接改变状态,使得代码更为简洁。此外,Pinia 将状态划分到各个独立的 store 中,这使得状态管理更为清晰和灵活。