【vue3】Pinia是什么?实现原理?手写Pinia!

前言:

本文只是说明pinia的核心功能及核心原理,它本身的功能是很多很复杂的,这里就不进行叙述,我们只需要掌握这个工具的核心功能即可。

1.是什么

Pinia是基于Vue 3的Composition API构建的状态管理库。它让你能够创建和管理多个store,通过调用createPinia激活一次,你能获取全应用的store访问权限。

2.主要特性

  • Pinia拥有独立的store,每个store都有自己的状态(state)和行为(action)等。
  • 你能调用store = useStore()直接使用和获取store。
  • Pinia全局只需要一次安装(通过app.use(createPinia())函数)。
  • 自动在DevTools中显示每次状态改变。

3.实现原理 

以下是对 Pinia 工作原理的总结:

1. 创建 Pinia 实例:   
   `createPinia()` 用于生成 Pinia 实例,这个实例你可以将其看作为一个全局的 store 容器,用来保存所有的 Vuex store。

2. 创建 Store:  
   使用 `createStore` 可以创建一个新的 store,这个 store 可看做是一个独立的状态管理空间,其中包含了 state、getters 和 actions,被创建的 store 实例会被自动添加到 Pinia 实例中。

3. 使用 Store:  
   我们通过在组件中调用用 `createStore` 创建的 store 函数,来获取对应的 Pinia store 的实例。然后,我们就可以访问其中的 state、getters,或者执行 actions 里定义的方法。

4. 监听 Store 变化:  
   我们可以使用 Vue 的 `watch` 和 `watchEffect` 函数来监听 store 中 state 或 getters 的变化,以便在这些内容改变时执行相应的操作。

5. 整合到 Vue App 中:  
   创建的 Pinia 实例需要使用 `app.use()` 安装到 Vue App 中,以便 Pinia 与 Vue App 一同工作,提供全局的状态管理能力。

ps:

如果你已经熟悉 Vue 或 Vuex,那么你在学习和使用 Pinia 时应该会觉得很自然,因为其设计思想和使用方式与 Vue、Vuex 非常接近,但同时也提供了更加灵活和便利的特性。

 


3.手写pinia

简易版 Pinia 的实现中包括以下关键部分:

  1. 创建一个 Pinia 对象,它包含一个响应式的 Map,用于存储所有的 store。
  2. 设定在 Vue 类型系统 的安装方法,它将 Pinia 实例提供给整个 Vue 应用。
  3. 设定一个 createStore 方法,用于创建或获取一个 store。store 是通过处理选项参数(如:id, state, getters, actions)生成的。
  4. 设定一个 useStore 方法,通过 store id 来获取 store。使用 computed() 函数确保返回的 store 是响应式的。

具体代码实现: 

// 引入所需的 Vue Composition API 相关函数
import { createStore as createVuexStore, reactive, computed } from 'vue'

// 创建 Pinia 对象
function createPinia() {
    // 用 reactive 创建响应式存储对象
    const stores = reactive(new Map());

    return {
        // 安装 Pinia 到 Vue 应用
        install(app) {
            // 在 Vue 应用中注册 Pinia 实例
            app.provide('pinia', this);
        },

        // 创建名为 "createStore" 的方法,用于根据选项创建或获取 store
        createStore(options) {
            // 如果 stores 已经存在相应的 store,则直接返回这个 store
            if (stores.has(options.id)) {
                return stores.get(options.id);
            }

            // 使用 Vue createVuexStore 函数创建响应式 store
            const store = createVuexStore({
                id: options.id,
                state: options.state,
                getters: options.getters,
                actions: options.actions
            });

            // 将新创建的 store 添加到 stores 中
            stores.set(options.id, store);

            // 返回创建的 store
            return store;
        },

        // 使用 store 的名字获取 store
        useStore(id) {
            // 返回一个计算属性,其值为获取到的 store
            return computed(() => stores.get(id));
        }
    }
}

// 创建 Store
function createStore(options) {
    // 返回一个使用 store 的函数,需要在 setup() 中调用
    return function useStore(pinia = inject('pinia')) {
      // 调用 pinia 的 createStore 方法创建或获取对应的 store
        return pinia.createStore(options);
    }
}

export {
    createPinia,
    createStore
}

然后,是它的实际使用了:
 

  1. 首先,我们要在应用层面使用 createPinia 创建 Pinia 实例并安装到 Vue 应用中:
    import { createApp } from 'vue';
    import App from './App.vue';
    import { createPinia } from './pinia';
    
    // 创建 Pinia 实例
    const pinia = createPinia();
    
    // 创建 Vue 应用
    const app = createApp(App);
    
    // 使用 Pinia
    app.use(pinia);
    
    // 挂载到 DOM
    app.mount('#app');

  2. 然后,我们可以通过 createStore 方法创建一个名为 useCounterStore 的 store:
    import { createStore } from './pinia';
    
    export const useCounterStore = createStore({
        id: 'counter',
        state: () => ({
            count: 0
        }),
        getters: {
            isZero: state => state.count === 0
        },
        actions: {
            increment() {
                this.state.count++;
            }
        }
    });

  3. 在 Vue 组件中,可以使用 useCounterStore 来获取和使用这个 store:
    import { computed } from 'vue';
    import { useCounterStore } from './store';
    
    export default {
      setup() {
        const store = useCounterStore();
        
        // 使用状态
        console.log(store.state.count); // 0
        
        // 使用 getter 计算属性
        const isZero = computed(() => store.getters.isZero);
        console.log(isZero.value); // true
        
        // 使用 actions
        store.actions.increment();
        console.log(store.state.count); // 1
      }

    上文中已经描述了 get、set 和使用 store 中的 actions 的基本用法,下面我将说明如果你要监听store的变化应该如何操作。

    Vue 的 Composition API 提供了 `watch` 和 `watchEffect` 函数,能让你监听 reactive object (响应式对象)或者 ref (引用对象)的值变化。当你需要监听 store 中的数据变化时,可以使用这两个函数。

    以下示例展示了如何监听 state 和 getters 的变化:

    
    import { watch, watchEffect } from 'vue';
    import { useCounterStore } from './store';
    
    export default {
      setup() {
        const store = useCounterStore();
    
        // 监听 state 变化
        watch(() => store.state.count, (newCount, oldCount) => {
          console.log(`Count changed from ${oldCount} to ${newCount}`);
        });
    
        // 监听 getter 变化
        watch(() => store.getters.isZero, newVal => {
          console.log(`isZero changed to ${newVal}`);
        });
    
        // 使用 watchEffect 监听 state 变化,不需要提供一个函数作为源
        watchEffect(() => {
          console.log(`Count is now ${store.state.count}`);
        });
      }
    }
    

    在这个例子中,我们使用 `watch` 监听 count 和 isZero 的变化,当这两个值改变时,对应的回调函数就会被执行。同时我们也用 `watchEffect` 监听了 count,这样只要 count 变化,即使值还是原值,对应的回调函数也会执行。当你在组件 setup 函数中设置了监听,当组件卸载后,监听也会自动停止。


     

猜你喜欢

转载自blog.csdn.net/wanghaoyingand/article/details/134333228