[鼠年全马] W38 - 使用Vuex管理资料状态(上)


这週要来介绍一个很好用的套件 - Vuex

看到名称应该马上可以理解他就是Vue专案在使用的套件吧xD

有看过我之前的专案开发的文章的人,应该会发现我从来没有用过 Vuex
我也是最近这两週才开始接触它的~

趁着记忆犹新时赶快把它写起来~
如果有使用不当或是有误的地方再麻烦多指教http://img2.58codes.com/2024/emoticon41.gif


#Vuex是什么?

万用起手式来了~
所谓的Vuex是什么呢? 他可以做到哪些事呢?

官方是这么介绍它的:

Vuex是一个专为Vue.js应用程序开发的状态管理模式。
它採用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex也集成到Vue的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能。

blablabla...
当时看完这段介绍之后我还是不知道Vuex是在做什么xD

没关係我们继续往下看:

每一个Vuex应用的核心就是store(仓库)。
“store”基本上就是一个容器,它包含着你的应用中大部分的状态(state)。

到这边应该稍微可以理解原来它的用途是「管理资料状态的容器」


#为什么需要Vuex?

原本的做法就可以在每个元件中存放资料了,那为什么还要用Vuex呢?

通常我们的资料流向会是父传子,上层传至下层,保持数据单向流通
遇到需要从子层改变父层资料时可以使用 $emit() 呼叫父层方法进而改变数据
遇到兄弟同层之间的元件要互相影响时就会有困难了,我自己的做法是将资料放到父层再用父传子的方式处理
但是不论父传子还是兄弟互传的做法都非常的麻烦且繁琐

这时候Vuex就出现了!!

我们可以将需要用到传递的资料通通丢进Vuex管理
当元件需要使用资料时,可以使用 $store 轻鬆取得数据
且透过套件提供的 dispatch 方法,可以从任何元件去改变资料数据

那传递呢? 当然用不到啰~
透过Vuex我们可以把传递的方式取代掉,并且还是保持着资料数据单向流通


#Vuex内容

刚才有看到官方文件说「Vuex应用的核心就是store」
而 Store 就是存放资料状态的容器

那这个容器内包含着哪些东西呢?

state: 存放资料状态的物件,类似Vue元件中的 dataactions: 存放方法的物件,类似Vue元件中的 methods
除了改变资料状态以外的工作,都会在这边处理mutations: 负责做改变资料状态的动作getters: 取得资料状态的方法,在取得之前也可以在这先做一些资料处理,类似Vue元件中的 computed

以上四个项目会是基本常使用到的,其他还有像是

modules: 模组化的Vuex

#Vuex数据流向


在数据流向的部分
前端元件(component)会透过 ditpatch 呼叫 actions 方法
actions 再透过提交(commit)的方式呼叫 mutations
mutations 再做更新 state 中的资料状态的动作
state 更新后再将数据渲染到元件中

透过这个流程达到单向数据流的操作


#安装Vuex

基本介绍之后,就先来安装它吧~
这里以使用 Vue Cli 专案为主来说明

使用npm安装指令:

npm install vuex --save

官方还有提供其他方式如:

Yarn
yarn add vuex
script引用
<script src="/path/to/vue.js"></script><script src="/path/to/vuex.js"></script>

#建立基本的Store

安装完成之后来建立一个最简单的Store啰~

#Step 1

在专案下新增一个 /store 资料夹,资料夹内再新增一个 index.js 档:

src└── store    └── index.js

#Step 2

开启刚刚建立的 index.js 加入基本的程式码:

import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({    state: {        msg: "Hello Vuex!!"    },});

Step 3

在 main.js 中引用:

import store from './store'

store 要加进vue喔!!

new Vue({  ...,  store,}).$mount('#app')

#Step 4

上面步骤都完成之后可以来到元件中去抓看看 msg 啰~
在元件的 computed 中使用 $store.state 来取得资料数据,可以在 App.vue 中试试看是否能抓到并渲染在画面上:

//App.vue<template>  <div>    {{ myMsg }}  </div></template><script>export default {  name: "App",  computed: {    myMsg() {      return this.$store.state.msg;    },  },};

基本的 Store 就建立完成啰!!


#建立TodoList

接着我会用不包含任何功能的TodoList来介绍后面的操作

#Step 1

像刚才 msg 一样,我们在 Store 中建一个TodoList:

export default new Vuex.Store({    state: {        todolist: [            { id: 1, todo: "交女朋友", done: false },            { id: 2, todo: "财务自由", done: false },            { id: 3, todo: "当码农", done: true },        ],    },});

#Step 2

在 App.vue 中抓值并渲染:

<template>  <div>    <ul>      <li v-for="item in myTodo" :key="item.id">        {{ item.todo }} - {{ item.done ? "已完成" : "未完成" }}      </li>    </ul>  </div></template><script>export default {  name: "App",  computed: {    myTodo() {      return this.$store.state.todolist;    },  },};</script>

出来的画面长这样:
http://img2.58codes.com/2024/20118686uvaNgUU6mi.jpg

#Step 3

前置作业完成了,再来我要加上click事件来切换 [已完成] 及 [未完成] 的状态:

<li  ...  @click="todoDone(item.id, !item.done)">  ...</li>

对应的 todoDone() 方法:

methods: {  //id: 要修改状态的资料唯一码  //done: 要修改的值  todoDone(id, done) {    },},

#Step 4

再来很重要(应该从头到尾都很重要xD)
我们要使用 dispatch 来呼叫 actions
第一个参数设定要呼叫的 actions 名称
第二个参数设定要传入的值,有多个值的话就用物件的方式带入

假设要呼叫的 actions 名称也叫 todoDone,并且将 id & done 传进去:

todoDone(id, done) {  this.$store.dispatch("todoDone", { id, done });},

#Step 5

回到 /store/index.js 加入 todoDone():

actions: {    todoDone(context, { id, done }) {        },},

说明一下 actions 的参数结构,每个 actions 会有带两个参数: myActions(context, payload)

第一个参数 context 是个与store实例具有相同方法和属性的对象

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

我们在 context 中可以使用这些属性:

{     state, // 等同于`store.state`,若在模块中则为局部状态    rootState, // 等同于`store.state`,只存在于模块中    commit, // 等同于`store.commit`     dispatch , // 等同于`store.dispatch`     getters, // 等同于`store.getters`     rootGetters // 等同于`store.getters`,只存在于模块中 }
第二个参数 payload 是带入的参数内容(可不带)

#Step 6

接着我们可以在 actions 中使用 commit 将要修改的数据提交给 mutations 来更新:

todoDone(context, { id, done }) {    context.commit('TODOLIST', { id, done });},

第一个参数设定要提交给哪个 mutations 的名称
第二个参数设定要传入的值,有多个值的话就用物件的方式带入

通常actions会有一些资料面的逻辑处理,例如呼叫ajax等等,逻辑处理结束后才会提交到mutations
但範例中因为没有这层,所以看起来像是多做了一个没有用的动作

#Step 7

接着可以加入 mutations:

mutations: {    TODOLIST(state, { id, done }) {        },}

这边使用了常量替代Mutation 事件类型:

使用常量替代mutation 事件类型在各种Flux 实现中是很常见的模式。这样可以使linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个app 包含的mutation 一目了然
用不用常量取决于你——在需要多人协作的大型项目中,这会很有帮助。但如果你不喜欢,你完全可以不这样做。

说明一下 mutations 的参数结构,每个 mutations 会有带两个参数: myMutations(state, payload)

第一个参数 state 就是指存放资料状态的 state第二个参数 payload 是带入的参数内容(可不带)

#Step 8

最后就是更新资料状态
先抓到 state 中的 todolist:

let todolist = state.todolist;

使用阵列的 find() 方法抓到要改的那笔:

let todo = todolist.find((item) => {    return item.id === id;});

更新 done 值:

todo.done = done;

整段会是这样:

TODOLIST(state, { id, done }) {    let todolist = state.todolist;    let todo = todolist.find((item) => {        return item.id === id;    });    todo.done = done;},

也可以合併成这样:

TODOLIST(state, { id, done }) {    state.todolist.find((item) => {        return item.id === id    }).done = done;},

#结果

到这里就完成更新资料状态啰!!
来看看结果吧~
gif已死QQ


先到这啰~
下週继续来探讨模组化以及其他的功能!!
http://img2.58codes.com/2024/emoticon29.gifhttp://img2.58codes.com/2024/emoticon29.gifhttp://img2.58codes.com/2024/emoticon29.gif


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章