【Vue.js】Pinia 的基本认识和使用

什么是 Pinia ?

官方描述:Pinia 是一款符合直觉的 Vue.js 状态管理库,它允许你跨组件或页面共享状态。

Pinia 的优势是什么?

  • Devtools 支持

    • 追踪状态变化的时间线,并及时给予开发者反馈
    • 配合 Vue DevTools, 可以在组件中展示所用到的 Pinia Store
    • 让调试更容易的 Time travel
  • HMR 热更新

    • 不必重载页面即可修改 Store
    • 开发时可保持当前的 State
  • 自定义插件:可通过插件扩展 Pinia 功能

  • TypeScript 支持

    • 为 JS 开发者提供适当的 TypeScript 支持以及自动补全功能。
  • 支持服务端渲染

    • Pinia 不仅仅能在 SPA 应用中使用,而且在 SSR 应用 (比如 Nuxt.js)也能够运用

PiniaVuex 的对比:

PiniaVuex 都是 Vue.js 的状态管理仓库(容器),但是在设计理念上面,VuexPinia 有所不同:

  1. 是否遵循 Flux流思想:Vuex 的设计是参照了 Flux 思想进行设计的 (state 管理状态,actions 派发任务,mutations 更新 state,state 变化重新渲染视图);但是 Pinia 取消掉了 Flux 这一繁琐的操作流程,直接使用单向数据流修改(state 管理状态,actions 更改 state,state 变化重新渲染视图)

  2. 基于第一点, PiniaVuex继承 DevTool 的位置不同:Pinia的 state 变化是在 actions 中监听的,Vuex的 state 的变化是在 actions 中监听的

  3. 核心模块的理念不同:

    • Vuex的设计是基本遵循单一 store 的思想,而 Pinia允许你的项目存在多个 store,并且由 pinia 统一管理这些 store
    • Vuex 实现多模块的方式是 module 嵌套,而 Pinia实现多模块的方式是多个扁平化的 store 。
    • 相比之下,Pinia 更加便捷,因为它无需再考虑是否需要配置 modules 和开启 namespaced
  4. 配置项不同:Vuex的配置更倾向于 Options API 风格;而 Pinia的包容性更强,它既可以使用 Options API 定义,也可以使用 Setup 函数 (Composition API)进行定义

  5. 对于 TypeScript 的支持:Pinia 的支持程度更好,因为它一开始就是用 TypeScript 进行开发的,没有历史包袱。

Pinia 的基本使用:

概述:

使用 Pinia 总共有三步:

  1. 让 VueApp (Vue 实例) 使用上 pinia 实例
  2. 定义创建获取 PiniaStore 的 Hook
  3. 在组件中使用创建 PiniaStore 的 Hook创建一个 Store,直接使用即可

代码演示:

1. 让 VueApp (Vue 实例) 使用上 pinia 实例

js 复制代码
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';

const vueApp = createApp(App);

vueApp.use(createPinia());

vueApp.mount('#app');

2. 定义创建 PiniaStore 的 Hook

  • 选项式创建
js 复制代码
import { defineStore } from 'pinia';

const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  getters: {
    doubleCount() {
      return this.count * 2;
    }
  },
  actions: {
    addCount() {
      this.count += 1;
    }
  }
});

export default useCounterStore;
  • 组合式创建
js 复制代码
import { ref, computed } from 'vue';
import { defineStore } from 'pinia';

const useTodoListStore = defineStore('todoList', () => {
	const todoList = ref([]);

  const todoListCount = computed(() => todoList.value.length);

	function addTodo(todo) {
    if (!todo) {
      return;
    }
    todoList.value = [todo, ...todoList.value];
  }

  function removeTodo(id) {
    todoList.value = todoList.value.filter(item => item.id !== id);
  }

  function toggleTodo(id) {
    todoList.value = todoList.value.map(item => {
      if (item.id === id) {
        item.completed = !item.completed;
      }

      return item;
    });
  }
  
  return {
    todoList,
    todoListCount,

    addTodo,
    removeTodo,
    toggleTodo,
  };
});

export default useTodoListStore;

3. 在组件中使用创建 PiniaStore 的 Hook创建一个 Store,直接使用即可

html 复制代码
<script setup>
	import { ref } from 'vue';
  
  import useCounterStore from '@/store/counterStore';
  import useTodoListStore from '@/store/todoListStore';

  const counterStore = useCounterStore();
  const todoListStore = useTodoListStore();

  const addTodoInput = ref('');

  function handleAddTodoBtnClick() {
    const content = addTodoInput.value.trim();

    if (!content) {
      return;
    }

    const todo = {
      content,
      id: new Date().getTime(),
      completed: false
    };
    todoListStore.addTodo(todo);
  }
</script>

<template>
  <div class="container">
    <div class="counter">
      <h1>{{ counterStore.count }}</h1>
      <button @click="counterStore.addCount">ADD COUNT</button>
    </div>
    <hr />
    <div class="todo-list">
      <div class="add-todo-input">
        <input v-model="addTodoInput" placeholder="请输入待办项" />
        <button @click="handleAddTodoBtnClick">添加待办项</button>
      </div>
      <ul class="list">
        <li
          class="list-item"
          v-for="item of todoListStore.todoList"
          :key="item.id"
        >
          <input
            type="checkbox"
            :checked="item.completed"
            @click="todoListStore.toggleTodo(item.id)"
          />
          <span :style="{ textDecoration: item.completed ? 'line-through' : '' }">
            {{ item.content }}
          </span>
          <button @click="todoListStore.removeTodo(item.id)">
            REMOVE TODO
          </button>
        </li>
      </ul>
    </div>
  </div>
</template>

像这样,Pinia 的创建和基本使用就完成了!

相关推荐
腾讯TNTWeb前端团队3 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰7 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪7 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪7 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy8 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom8 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom8 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom8 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom8 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom9 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试