Vue 状态管理 Vue CLI

Vue 状态管理 & Vue CLI

  • 1、状态管理
  • 2、集中状态管理
    • 2.1 Vuex
      • 2.1.1 Vuex核心概念
      • 2.1.2 Vuex Store实例
      • 2.1.3 Vuex Getter
      • 2.1.4 Vuex Mutation
      • 2.1.4 Vuex Actions
      • 2.1.4 Vuex Module
    • 2.2 Pinia
      • 2.2.1功能增强
  • 3、Vuex 实现原理
  • 4、Pinia 实现原理
  • 5、CLI
    • 5.1 实现

1、状态管理

将一个数据变为状态的方法:

  • ref

  • reactive

  • provide + inject,深层状态传递

  • Vuex、Pinia,集中状态管理

  • eventbus,状态管理,响应式数据解决不了的问题,我们尝试使用发布订阅模式来解决

怎么选择:

  • 如果是组件内部状态、父子组件状态管理,选择 ref、reactive、computed
  • 如果是深层组件状态,选择 provide + inject 来处理
    • 换肤、主题
    • 国际化
  • 跨组件、跨模块的状态,选择 vuex、Pinia

2、集中状态管理

在 Vue 最重要就是 数据驱动 和 组件化,每个组件都有自己 data ,template 和 methods。data是数据,我们也叫做状态,通过 methods 中方法改变状态来更新视图,在单个组件中修改状态更新视图是很方便的。
当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:

  • 多个视图依赖于同一状态。
  • 来自不同视图的行为需要变更同一状态。

2.1 Vuex

2.1.1 Vuex核心概念

  • Action:响应在视图上的用户输入导致的状态变化。
  • State:驱动应用的数据源;
  • Mutation(在pinia中被取消)
  • View:以声明方式将状态映射到视图;
  • Module:数据模块

ps: react:action -> reducer -> state -> view

在这里插入图片描述

  • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  • 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

2.1.2 Vuex Store实例

import { createStore } from 'vuex';const defaultState = {count: 0,
};// Create a new store instance.
export default createStore({state() {return defaultState;},mutations: {increment(state) {state.count++;},},actions: {increment(context) {context.commit('increment');},},
});import { createApp } from 'vue';
import App from './App.vue';
import store from './store';createApp(App).use(store).mount('#app');

Vue 组件中展示状态

 // 创建一个 Counter 组件
const Counter = {template: `<div>{{ count }}</div>`,computed: {count () {return store.state.count}}
}

mapState 辅助函数
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性:

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'export default {// ...computed: mapState({// 箭头函数可使代码更简练count: state => state.count,// 传字符串参数 'count' 等同于 `state => state.count`countAlias: 'count',// 为了能够使用 `this` 获取局部状态,必须使用常规函数countPlusLocalState (state) {return state.count + this.localCount}})
}

对象展开运算符
对象展开运算符(opens new window),将多个对象合并为一个,将最终对象传给 computed 属性

computed: {localComputed () { /* ... */ },// 使用对象展开运算符将此对象混入到外部对象中...mapState({// ...})
}

2.1.3 Vuex Getter

有时候从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数:(使用计算属性)

computed: {doneTodosCount () {return this.$store.state.todos.filter(todo => todo.done).length}
}

如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
Getter 接受 state 作为其第一个参数:

const store = createStore({state: {todos: [{ id: 1, text: '...', done: true },{ id: 2, text: '...', done: false }]},getters: {doneTodos (state) {return state.todos.filter(todo => todo.done)}}
})

通过属性访问
Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值:

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]

通过方法访问

getters: {// ...getTodoById: (state) => (id) => {return state.todos.find(todo => todo.id === id)}
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

mapGetters 辅助函数

mapGetters 辅助函数:将 store 中的 getter 映射到局部计算属性:
用法类似mapState

 import { mapGetters } from 'vuex'export default {// ...computed: {// 使用对象展开运算符将 getter 混入 computed 对象中...mapGetters(['doneTodosCount','anotherGetter',// ...])}
}

如果你想将一个 getter 属性另取一个名字,使用对象形式:

...mapGetters({// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`doneCount: 'doneTodosCount'
})

2.1.4 Vuex Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)
回调函数:实际进行状态更改的地方,并且它会接受 state 作为第一个参数
事件类型:store.commit(type)
定义:

const store = createStore({state: {count: 1},mutations: {increment (state) {// 变更状态state.count++}}
})

要唤醒一个 mutation 处理函数,你需要以相应的 type 调用 store.commit 方法:

store.commit('increment')

Payload

你可以向 store.commit 传入额外的参数,即 mutation 的载荷(payload):

// ...
mutations: {increment (state, n) {state.count += n}
}// ..
store.commit('increment', 10)

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:

// ...
mutations: {increment (state, payload) {state.count += payload.amount}
}
// ...
store.commit('increment', {amount: 10
})

对象风格的提交方式

store.commit({type: 'increment',amount: 10
})

重要:Mutation 必须是同步函数

2.1.4 Vuex Actions

Actions存在的意义是假设你在修改state的时候有异步操作,vuex作者不希望你将异步操作放在Mutations中,所以就给你设置了一个区域,让你放异步操作,这就是Actions。

const store = createStore({state: {count: 0},mutations: {increment (state) {state.count++}},actions: {increment (context) {context.commit('increment')}}
//  actions: {
//  increment ({ commit }) {
//        commit('increment')
//    }
//   }
})

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
分发 Action:

Action 通过 store.dispatch 方法触发:

store.dispatch('increment')

我们直接分发 mutation 岂不更方便?实际上并非如此,还记得 mutation 必须同步执行这个限制么?
Action 就不受约束!我们可以在 action 内部执行异步操作:

actions: {incrementAsync ({ commit }) {setTimeout(() => {commit('increment')}, 1000)}
}

Actions 支持同样的载荷方式和对象方式进行分发:

// 以载荷形式分发
store.dispatch('incrementAsync', {amount: 10
})// 以对象形式分发
store.dispatch({type: 'incrementAsync',amount: 10
})

2.1.4 Vuex Module

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

const moduleA = {state: () => ({ ... }),mutations: { ... },actions: { ... },getters: { ... }
}const moduleB = {state: () => ({ ... }),mutations: { ... },actions: { ... }
}const store = createStore({modules: {a: moduleA,b: moduleB}
})store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

2.2 Pinia

核心概念

  • State

  • Getter

  • Action

  • 第一种是选项式写法

export const useCounterStore = defineStore("counter", {state: () => ({ count: 0 }),getters: {doubleCount: (state) => state.count * 2,},actions: {async increment() {await sleep(1000);this.count++;},},
});
  • 第二种是 composition api 写法
// 推荐用这种方式
export const useCounterStore = defineStore("counter", () => {const count = ref(0);const doubleCount = computed(() => count.value * 2);const increment = async () => {await sleep(1000);count.value++;};return { count, doubleCount, increment };
});

在 Setup Store 中

  • ref() 就是 state 属性
  • computed() 就是 getters
  • function() 就是 actions

2.2.1功能增强

插件化机制

  1. 可以增强 Pinia 能力
  2. 可以在 Pinia 加载时初始化一些数据,提供给应用使用

本质是一个函数,参数是 Pinia 实例内容,返回一个对象

function loggerPlugin() {console.log("hello");
}
export function piniaLogger(context: PiniaPluginContext) {// console.log('🚀 ~ piniaLogger ~ context:', context)context.store.$onAction((...args) => {console.log(`[🍍] ${name} with payload`, args);});// return {//   logger: "I am pinia logger",// };
}

插件既可以给定额外初始化 pinia 状态,也可以增强 Pinia 功能(日志)

3、Vuex 实现原理

各模块在核心流程中的主要功能:

  • Vue Components:Vue组件。HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
  • dispatch:操作行为触发方法,是唯一能执行action的方法。
  • actions:操作行为处理模块。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。
  • commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
  • mutations:状态改变操作方法。是Vuex修改state的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。
  • state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。
  • getters:state对象读取方法。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象。

不管是 Vue 还是 React,全局状态的方案基本都是基于发布订阅模式实现

4、Pinia 实现原理

Pinia 的实现原理核心内容与 Vuex 类似,发布订阅模式机制以及状态管理逻辑。除此以外,Pinia 比 Vuex 多了一些对于 Composition API 的支持机制

看源码的顺序:

  1. createPinia.ts,入口
    app.provide(piniaSymbol, pinia)
    app.config.globalProperties.$pinia = pinia
  2. vue-demi,轻量的 Vue3 钩子库,一般你去封装插件,都会用它
  3. store.ts
  4. subscriptions.ts

5、CLI

三种方案可以选择

  • Vue2 CLI,https://cli.vuejs.org/

  • Vue3 create,https://github.com/vuejs/create-vue

  • Vite Vue,https://vitejs.dev/guide/,pnpm create vite my-vue-app --template vue-ts

  • Vue CLI 创建应用:npm install -g @vue/cli,vue create hello

  • vue-create 创建:npm create vue@3

我们说的 Vue CLI 其实包含两个,一个是早期的 Vue CLI,打包基于 webpack,另一个是最新的 CLI,打包基于 vite

5.1 实现

  1. 模板库,用于创建新项目的模板,https://github.com/vuejs/create-vue/tree/main/template/base
  2. cli.ts (配置脚手架)

cli.ts的部分配置

// 用来人机交互完成后选择的变量let result: {projectName?: string;shouldOverwrite?: boolean;packageName?: string;needsTypeScript?: boolean;needsJsx?: boolean;needsRouter?: boolean;needsPinia?: boolean;needsVitest?: boolean;needsE2eTesting?: false | "cypress" | "nightwatch" | "playwright";needsEslint?: boolean;needsPrettier?: boolean;needsDevTools?: boolean;} = {};

CLI:通过命令行获得用户的意愿,根据这些意愿参数,组装模板,然后生成项目

补充资料:monorepo template:https://github.com/NiGhTTraX/ts-monorepo
pnpm workspace + turborepo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/876257.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【CG】计算机图形学(Computer Graphics)基础(其贰)

0 学习视频 B站GAMES101-现代计算机图形学入门-闫令琪 ※ 接上文【CG】计算机图形学&#xff08;Computer Graphics&#xff09;基础&#xff08;其壹&#xff09; 7 光线追踪 7.1 为什么需要光线追踪&#xff1f; 光栅化无法妥善处理全局效果 &#xff08;软&#xff09;阴…

一天搞定React(5)——ReactRouter(下)【已完结】

Hello&#xff01;大家好&#xff0c;今天带来的是React前端JS库的学习&#xff0c;课程来自黑马的往期课程&#xff0c;具体连接地址我也没有找到&#xff0c;大家可以广搜巡查一下&#xff0c;但是总体来说&#xff0c;这套课程教学质量非常高&#xff0c;每个知识点都有一个…

MATLAB基础:函数与函数控制语句

今天我们继续学习Matlab中函数相关知识。 API的查询和调用 help 命令是最基本的查询方法&#xff0c;可查询所有目录、指定目录、命令、函数。 我们直接点击帮助菜单即可查询所需的API函数。 lookfor 关键字用于搜索相关的命令和函数。 如&#xff0c;我们输入lookfor inpu…

开源物联网网关ThingsBoard IoT Gateway

前几天测试了Neuron&#xff0c;这是一个令人印象深刻的平台&#xff0c;不过它不能算是完全免费的平台&#xff0c;因为它还是有商业许可要求的&#xff0c;挺贵的&#xff0c;大几万的&#xff0c;而且它有走向闭源的趋势。所以也在寻找它的替代方案。 今天看到一个ThingsBo…

Django项目中报错:django.template.exceptions.TemplateDoesNotExist: index.html

访问127.0.0.1&#xff1a;8000访问出错 查看报错原因 到Django项目当中找到settings.py&#xff0c;找到TEMPLATES中的DIRS: 添加如下代码&#xff0c;并导入OS模块&#xff1a; "DIRS": [os.path.join(BASE_DIR,templates)] 再次访问IP地址&#xff1a;

C++(入门1)

C参考文档 Reference - C Reference C 参考手册 - cppreference.com cppreference.com 第一个C程序 #include<stdio.h> int main() {printf("Hello C\n");return 0; }由上述代码可知C是兼容C语言 第一个C标准程序 #include<iostream> using names…

【机器学习】智驭未来:机器学习如何重塑制造业的转型与升级

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f50d;1. 引言&#x1f4d2;2. 机器学习重塑制造业生产流程&#x1f338;预测性维护&#xff1a;减少停机时间&#xff0c;提高设…

实现共模噪声电流相互抵消的方法

共模传导路径中噪声电流相互抵消&#xff0c;从而使总的共模电流减小&#xff0c; 终达到降噪的目的。目前为实现共模噪声电流相互抵消&#xff0c;主要是采用动点电容抵消法。 动点电容抵消法原理 动点电容抵消法就是选取合适的动点&#xff0c;添加原副边跨接电容&#xff0c…

黑马头条Day10-定时计算热点文章、xxl-job

一、今日内容 1. 需求分析 目前实现的思路&#xff1a;从数据库直接按照发布时间倒序查询 问题&#xff1a; 如果访问量比较大&#xff0c;直接查询数据库&#xff0c;压力较大新发布的文章会展示在前面&#xff0c;并不是热点文章 2. 实现思路 解决方案&#xff1a;把热点…

CCS(Code Composer Studio 10.4.0)编译软件中文乱码怎么解决

如果是所有文件都出现了中文乱码这时建议直接在窗口首选项中修改&#xff1a;选择"Window" -> "Preferences"&#xff0c;找到"General" -> "Workspace"&#xff0c;将"Text file encoding"选项设置为"Other&quo…

深度解析Linux-C——函数和内存管理

目录 函数指针&#xff1a; 指针函数&#xff1a; 参数为指针的函数&#xff1a; 参数为数组的函数&#xff1a; C语言内存管理 stdlib.h头文件常用函数介绍 1、局部变量 2、全局变量 3、 堆空间变量 4、静态变量 5、常量 函数指针&#xff1a; 指向函数的指针&#…

Linux文件与相关函数的知识点3

main函数参数 int main(int argc,char *argv[]) { return 0; } C语言规定了main函数的参数只能有两个&#xff0c;一个是argc,一个是argv并且&#xff0c;argc只能是整数&#xff0c;第二个必须是指向字符 串的指针数组。 argc: 参数表示命令行中参数的个数&#xff0…

Java实现七大排序(二)

一.交换排序 1.冒泡排序 这个太经典了&#xff0c;每个学编程都绕不开的。原理跟选择排序差不多&#xff0c;不过冒泡排序是直接交换。 public static void bubbleSort(int[] array){for (int i 0; i < array.length - 1; i) {for (int j 0; j < array.length-1-i; j…

域内攻击手法——AS-REP Roasting攻击和Kerberoasting攻击

一、AS-REP Roasting攻击 1、AS-REP Roasting攻击原理 AS-REP Roasting是一种对用户账户进行离线爆破的攻击方式。但是该攻击方式使用上比较受限&#xff0c;因为其需要用户账户设置不要求Kerberos 预身份验证选项&#xff0c;而该选项默认是没有勾选的。Kerberos 预身份验证…

20240727 每日AI必读资讯

&#x1f310;OpenAI向Google宣战&#xff0c;重磅推出AI搜索引擎SearchGPT &#xff01; - 将 AI 与实时网络信息结合 提供生成式UI结果 - SearchGPT 结合网络最新信息可以直接回答问题&#xff0c;同时注明相关来源链接。 - 还可以像与人对话一样提出后续问题&#xff0c;…

进程概念(三)----- fork 初识

目录 前言1. pid && ppid2. forka. 为什么 fork 要给子进程返回 0&#xff0c; 给父进程返回子进程的 pid &#xff1f;b. 一个函数是如何做到两次的&#xff1f;c. fork 函数在干什么&#xff1f;d. 一个变量怎么做到拥有不同的内容的&#xff1f;e. 拓展&#xff1a;…

小红书电商首提“生活方式电商”定义,个性化需求也能做成好生意

近日&#xff0c;小红书发布COO柯南与经济学者薛兆丰的对谈视频。对谈中柯南首次对外定义&#xff0c;小红书电商是“生活方式电商”。 柯南表示&#xff0c;生活方式电商是让用户在小红书买到的&#xff0c;不仅是好产品&#xff0c;也是一种向往的生活。 随着生活方式的多元…

【初阶数据结构】9.二叉树(4)

文章目录 5.二叉树算法题5.1 单值二叉树5.2 相同的树5.3 另一棵树的子树5.4 二叉树遍历5.5 二叉树的构建及遍历 6.二叉树选择题 5.二叉树算法题 5.1 单值二叉树 点击链接做题 代码&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* …

PID 控制实验 - 整定实验

Arduino PID Arduino-PID-LibraryArduino-PID-AutoTune-Library PID控制实验 – 制作测试台 PID Control Experiment – Making the Testing Rig PID (Proportional, Integral, Derivative) control is a classic control algorithm that I have used for a few projects,…

Java面试还看传统八股文?快来看看这个场景题合集吧【附PDF】

以下就是这份面试场景文档↓ 这里有什么&#xff1f; ↓↓ 1.针对 2024 年面试行情的变化设计的面试场景题以及回答思路 2. 如何快速通过面试的详细攻略 3. 简历优化技巧 1.知己知彼才能百战百胜&#xff0c;如何做好面试前的准备工作 场景题答案以及更多场景题八股文一线大…