Vuejs中Vuex是什么意思?结合实例来搞清楚

已收录   阅读次数: 697
2021-10-3117:49:18 发表评论
摘要

接着前文继续深化学习Vue.js相关内容,前文基础内容可以看下方的前情提要,也可以在本站搜索关键词Vue,会有更多精彩的相关内容,本篇内容主要是聊聊Vue.js中的Vuex是什么东东,以及结合实例来看看它是如何使用的……

分享至:
Vuejs中Vuex是什么意思?结合实例来搞清楚

开篇寄语

接着前文继续深化学习Vue.js相关内容,前文基础内容可以看下方的前情提要,也可以在本站搜索关键词Vue,会有更多精彩的相关内容,本篇内容主要是聊聊Vue.js中的Vuex是什么东东,以及结合实例来看看它是如何使用的。

前情提要

内容详情

以下内容是以Vue 3位范例,虽然与Vue 2差别不是很大。

Vuex 是 Vue.js 的官方Store库和状态管理模式。它的优势是作为 Vue 的第一个Store,因此已被世界各地成千上万的开发人员在数千个项目中使用,并且经过时间测试证明是有效的。让我们来看看它是如何工作的。

请注意,如果您使用的是 Vue 2,您将需要使用 Vuex 3。我将展示与 Vue 3 兼容的 Vuex 4 中的示例,但只有一些不同之处,因此这里描述的大部分内容都适用。

如何安装?

npm install vuex@4 --save
# or with yarn
yarn add vuex@4

然后通过类似于 Vue 3 的 createApp() 函数的 createStore() 函数实例化它,比如:

// store/index.js
import {createStore} from 'vuex'
export default createStore()

最后,像其他任何 Vue 插件一样使用 use() 方法向 Vue 注册它。

// main.js
import { createApp } from 'vue'
import store from '@/store' // short for @/store/index
const app = createApp({ /* your root component */ })
app.use(store)

Vuex特性

  • 是官方解决方案
  • 是最长寿且经过实战考验的解决方案
  • 在 Vue 社区中很受欢迎,拥有丰富的可用教育资源(因此可能最适合让新开发人员加入项目)
  • 与 Vue Devtools 完美集成,提供出色的开发体验

Store定义

Vuex 中的存储是通过传递给 createStore 函数的对象定义的。该对象可以具有以下任何属性:state, getters, mutations, and actions。

// store/index.js
export default createStore({
  state:{},
  getters:{},
  mutations: {},
  actions:{}
})

分别看一下都是代表什么意思:

state

Store的状态在 state 属性中定义。状态只是一个花哨的词,意思是你想在你的Store中保存的数据。您可以将其视为组件上的数据属性,但可用于您的任何组件。你可以把你想要的任何类型的数据放在这里。此外,状态中定义的不同属性可以是您喜欢的任何数据类型,例如对象、数组、字符串、数字等。

state:{
  user: { name: 'John Doe', email: '[email protected]', username: 'jd123'},
  posts: [],
  someString: 'etc'
}

为了在任何组件模板中访问Store的状态,您可以使用 $store.state[propertyNameHere]。例如,为了在配置文件组件中访问用户名,我们执行以下操作:

// ProfileComponent.vue
<template>
  <h1>Hello, my name is {{$store.state.user.name}}</h1>
</template>

或者我们可以使用计算属性稍微清理模板。

// ProfileComponent.vue
<template>
  <h1>Hello, my name is {{name}}</h1>
</template>
<script>
export default{
  computed:{
    name(){ return this.$store.user.name }
  }
}
</script>

随着您继续从组件访问Store的状态,以这种方式制作计算属性会变得越来越冗长。为了让事情变得轻松,您可以使用其中一个 Vuex 辅助函数 mapState,将我们希望在组件中访问的状态中的顶级属性数组传递给它。

<template>
  <h1>Hello, my name is {{user.name}}</h1>
</template>
<script>
export default{
  computed:{
    ...mapState(['user'])
  }
}
</script>

Getters

除了存储在状态中的数据本身之外,Vuex 存储还可以拥有所谓的“getter”。您可以将 getter 视为计算属性的存储版本,就像计算属性一样,它们基于依赖关系进行缓存。 Vuex 中的所有 getter 都是在“getters”属性下定义的函数,并接收状态以及所有其他 getter 作为参数。然后从函数返回的就是那个 getter 的值。

{
  state:{
   posts: ['post 1', 'post 2', 'post 3', 'post 4']
  },

  // the result from all the postsCount getters below is exactly the same
  // personal preference dicates how you'd like to write them
  getters:{
    // arrow function
    postsCount: state => state.posts.length,

    // traditional function
    postsCount: function(state){
      return state.posts.length
    },

    // method shorthand
    postsCount(state){
      return state.posts.length
    },

    // can access other getters
    postsCountMessage: (state, getters) => `${getters.postsCount} posts available`
  }
} 

访问 store 的 getter 与访问 state 非常相似,示例如下:

// FeedComponent.vue
<template>
  <p>{{$store.getters.postsCount}} posts available</p>
</template>

您还可以在组件中使用计算属性或辅助函数(这次是 mapGetters),就像state一样。

// FeedComponent.vue
<template>
  <p>{{postsCount}} posts available</p>
</template>
<script>
import {mapGetters} from 'vuex'
export default{
  computed:{
    ...mapGetters(['postsCount'])
  }
}
</script>

Mutations and Actions

  • Mutation总是同步的,并且是唯一可以直接改变状态的东西。Mutation只负责更改单个数据。
  • Actions可以是同步的或异步的,不应该直接改变状态而是调用突变。操作可以调用多个突变。

此外,这里还有更多信息和最佳实践。

  • Mutation
    • 大写突变名称的约定
    • 通过 commit('MUTATION_NAME', payload) 调用
    • 有效载荷是可选的
    • 不应该包含是否改变数据的任何逻辑
    • 最佳做法是仅从您的操作中调用它们(即使您确实有权在组件中调用它们)
  • Actions
    • 可以从Store中的其他操作中调用
    • 是从组件内部更改状态的主要方式
    • 通过 dispatch('actionName', payload) 调用
    • 有效载荷是可选的
    • 可以包含改变或不改变什么的逻辑
    • 良好的做法是先定义为异步,这样如果逻辑从同步更改为异步,您调度操作的位置就不必更改

来一个实际案例:

{
  state: {
    posts: ['post 1', 'post 2', 'post 3', 'post 4'],
    user: { postsCount: 2 }
    errors: []
  }
  mutations:{
    // convention to uppercase mutation names
    INSERT_POST(state, post){
            state.posts.push(post)
    },
    INSERT_ERROR(state, error){
        state.errors.push(error)
    },
    INCREMENT_USER_POSTS_COUNT(state, error){
      state.user.postsCount++
    }
  },
  actions:{
    async insertPost({commit}, payload){
       //make some kind of ajax request 
       try{
         await doAjaxRequest(payload)

         // can commit multiple mutations in an action
         commit('INSERT_POST', payload)
         commit('INCREMENT_USER_POSTS_COUNT')
       }catch(error){
        commit('INSERT_ERROR', error)
       }
    }
  }
}

为了说明起见,这些变更似乎过于简化,但在生产代码库中,变更应该同样简短,因为它们只负责更新单个状态。

如果你是 Vuex 的新手,Mutations and Actions之间的区别一开始可能有点麻烦,但过一段时间你就会习惯。尽管编写Mutations并不是最令人愉快的,因为它会产生大量的样板文件,但对于调试应用程序的时间旅行的开发工具体验来说是必要的。然而,Vuex 5 的 RFC 表明,未来将不再需要突变,这样我们就可以跳过突变样板并仍然享受 devtools 体验。

最后,要从组件运行操作,您可以调用 store 上的 dispatch 方法并将要运行的操作的名称作为第一个参数传递给它,并将有效负载作为第二个参数传递给它。

// PostEditorComponent.vue
<template>
  <input type="text" v-model="post" />
  <button @click="$store.dispatch('insertPost', post)">Save</button>
</template>

从组件的方法中分派您的操作也很常见。

// PostEditorComponent.vue
<template>
  <input type="text" v-model="post" />
  <button @click="savePost">Save</button>
</template>
<script>
export default{
  methods:{
    savePost(){
      this.$store.dispatch('insertPost', this.post)
    }
  }
}
</script>

和 state 和 getter 一样,您可以使用辅助函数将操作映射到组件方法。

// PostEditorComponent.vue
<template>
  <input type="text" v-model="post" />
  <button @click="insertPost(post)">Save</button>
</template>
<script>
import {mapActions} from 'vuex'
export default{
  methods:{
    ...mapActions(['insertPost'])
  }
}
</script>

在模块中组织

随着应用程序的文件越来越多,您会发现单个全局存储文件变得难以忍受且难以快速找到文件。 Vuex 对此的解决方案称为模块,它允许您根据域逻辑(例如一个用于帖子的文件、另一个用于用户的文件、另一个用于产品的文件等)将您的Store划分为单独的文件,然后访问state、getter等来自特定命名空间下的模块。

您可以在官方 Vuex 文档中查看模块的确切实现细节。

Vue devtools

最后,如果我不强调 Vuex 与 Vue Devtools 的配合,我将是失职。为了使用 Vuex 3 处理 Vue 2 项目,您在 devtools 中有一个专用的 Vuex 选项卡,它允许您查看已提交变更的运行列表,到特定变更的时间旅行以查看您的应用程序和状态时间点,甚至将应用程序恢复到特定Mutations时的状态。

总结

Vuex 是 Vue.js 的经过实战测试和流行的Store,但不是您可以使用的唯一选择。对于轻量级应用程序,可以试试新成员新成员:Pinia。

  • 我的微信
  • 微信扫一扫加好友
  • weinxin
  • 我的微信公众号
  • 扫描关注公众号
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: