024 Vuex状态管理工具

105 阅读3分钟

Vuex状态管理工具

vuex是什么?

vuex是一个专门为vue.js应用程序开发的状态管理模式,采用集中式存储管理应用的所有组件的状态,解决多组件间数据通信

使用vuex的好处:

  1. 数据的存取一步到位,不需要层层传递
  2. 数据的流动非常清晰
  3. 存储在Vuex中的数据都是响应式的

什么样的数据适合存储到vuex中?

需要共享的数据。

vuex的作用:频繁、大范围的数据共享。

vue官方提供的独立于组件体系之外的,管理公共数据的工具。

配置

如果采用脚手架方式进行创建,无需任何操作,可以忽略此步骤。

新建store文件->index.js,进行如下配置,在mian.js中进行引入

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export defult new Vuex.store({
    // 数据,相当于data
    state: {
        
    },
    getters: {
        
    },
    // 里面定义方法,操作state方法
    mutations: {
        // 每一项都是一个函数,可以声明两个形参
        mutation名1(state[,载荷]) {
         
        },
    	mutation名2(state[,载荷]) {
            
        },
    },
    // 操作异步操作mutation
    actions: {
                             
    },
    modules: {
        
    },
})

mian.js中

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app')

Vuex 五个概念

vuex分为五个大块:

  1. state:统一定义公共数据(类似于data)
  2. mutations:使用它来修改数据(类似于methods)
  3. getters:类似于computed(计算属性,对现有的状态进行计算的到新的数据)
  4. actions:发起异步请求
  5. modules:模块拆分

在项目中安装和配置Vuex

整体步骤:

  1. 安装
  2. 配置
    1. 创建Vuex.store实例
    2. 向Vue实例注入store
  3. 使用。在组建中使用store

步骤说明:

  1. 安装包

    进入项目目录,安装包

  2. 实例化store

​ 与router一样,当我们在项目中使用Vuex之后,为了方便代码维护,我们一般需要做特殊的目录调整,约定的结构如下。

根组件
└── src
    ├── main.js
    ├── router
    │   └── index.js   # 路由
    └── store
        └── index.js   # vuex

​ 在store/index.js中放置具体的代码如下:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
    state() {
        return {
            // 就是公共的数据,所有的组件都可以使用
            count: 100
        }
    }
})
export default store
  1. 向Vue实例注入store

​ 在src/main.js中:导入store,并注入Vue实例

// 1. 导入store
import store from './store'

new Vue({
    store // 注入vue实例
})
  1. 在组件中使用store

    在任意组件中,通过this.$store.state来获取公共数据。

Vuex-state定义公共数据并在组件中使用

概念:State 本质上就是Object 对象

state 的作用是:保存公共数据(多组件中共用的数据)

state 是响应式的:如果修改了数据,相应的在试图上的值也会变化。

组件访问state 数据的第一种方式

在每个Vue组件中,可以通过 this.$store.state.全局数据名称访问store中的数据

定义公共数据格式

new Vuex.store({
    state() {
        return 属性名:属性值
    }
})

使用公共数据:

在组件中,通过this.$store.state.属性名 来访问。

在模板中,可以省略this而直接写成: {{ $store.state.属性名 }}

组件访问state数据的第二种方式

import { mapState } from 'vuex'

export default {
    name: 'left',
    computed: {
        ...mapState(['count']),
    },
}

小结:

  • 直接使用:this.$store.state.XXX

  • map辅助函数:

    computed: {
        ...mapState(['XXX']),
        ...mapState({'新名字':'XXX'})
    }
    

Vuex用mutations修改公共数据

Mutation 本质上是javascript函数,专门用来更新Store中的数据。

特点: 想要修改State中的数据,只能调用mutation方法,它是vuex中用来修改公共数据的唯一入口。

好处:能够确保修改来源的唯一性,方便调试和后期维护。

在定义时:它的第一个参数是state,第二个参数是载荷。

在调用时:用this.$store.commit('mutation名', 载荷)来调用

注意:Mutation必须是同步函数,Mutation里面不能放异步代码。

**定义格式:**如下

new Vue.store({
    state: {
        count: 100,
    },
    mutations: {
        // 每一项都是一个函数,可以声明两个形参
        addCount(state,num){
        	state.count =+ state.count + num
        },
    	reduce(state) {
            state.count--
        },
    }
})

每一项都是一个函数,可以声明两个形参:

  • 第一个参数是必须的,表示当前的state。在使用时不需要传入;
  • 第二个参数是可选的,表示载荷,是可选。在使用的时候要传入;

使用格式

// this.$store.commit('mutation名',实参)

methods: {
    clickAddBtn() {
        this.$store.commit('addCount',10)
    },
    clickReduceBtn() {
        this.$store.commit('reduce')
    },
}

这里的commit是固定方法。

mapMutations辅助函数

基于Vuex提供的mapMutations辅助函数,可以方便的吧Store中指定的方法,映射为当前组件的methods。

<button @click="clickAddBtn()"></button>
 
<script>
// 1. 按需导入 mapMutations 辅助函数 
import { mapMutations } from 'vuex'
    export default {
        methods: {
            // 从vuex中把clickAddBtn 映射为当前组件的methods方法
            ...mapMutations(['clickAddBtn'])
        },
    }
</script>

小结:

  • 直接使用: this.$store.commit('mutation名',参数)

  • map辅助函数:

    methods: {
        ...mapMutations(['mutation名']),
        ...mapMutations({'新名字': 'mutation名'}),
    }
    

vuex-mutations拓展理解

  1. 问: 为啥是store.commit(mutation的名),而不是store.commit('mutation的名字'),而不是store.mutations的名字?

    答:Vuex中的非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state 作为第一个参数。

  2. 数据不可以在该组件内部直接修改吗?

    答:不能。虽然语法上不报错,也有响应式的特点。但是不推荐。特别是在严格模式下会报错。若将vue创建store的时候传入strict: true,开启严格模式,那么任何修改state的操作,只要不经过mutation的函数,vue就会报错。

  3. 可以传递多个数据吗?

    答:参数只能有一个:下面写法是不对的:

    this.$store.commit('setURL',url,host)  // host这个参数将无法被接收到
    

    如果希望传递复杂的数据,第二个参数可以是对象或者数组,例如:

    this.$store.commit('setURL', { url, host })
    

Vuex-用getters的派生状态

作用: 它是Vuex中的计算属性,当Store数据源发生变化时,Getter 的返回值会自动更新。

访问 Getter 的你第一种方式

定义格式:

new Vuex.store({
    getters: {
        // state 就是上边定义的公共数据state
        getter的名字1(state) {
            return 要返回的值
        },
    }
})

state就是上边定义的公共数据state

使用格式:

在组件中通过: $store.getters.getter的名字 来访问。

访问 getter 的第二种方式

基于 mapGetters 辅助函数,可以把 store 中的 getter 映射为当前组件的计算属性。

map辅助函数:

computed: {
    ...mapGetters(['XXX']),
    ...mapGetters({ '新名字': 'xxx' })
}
<p>
    完成状态: {{ isDone }}
</p>

<script>
import { mapGetters } from 'vuex'
    export defult {
        computed: {
            ...mapGetter(['isDone'])
        }
    }
</script>

Vuex-actions发异步请求

Action 本质上是JavaScript 函数,专门用来处理 Vuex 中的异步操作。

actions介绍

  • actions 是Vuex 的一个配置项
  • 作用: 发异步请求获取数据局,调用mutations 来保存数据,将整个ajax 操作封装到 Vuex的内部。
  • 要点:
    • action内部可以发起异步请求操作
    • action 是简洁修改state的:是通过调用mutation 来修改state。

格式

定义格式:

new Vuex.store({
    actions: {
        // context 对象会自动转入,它与store 实例具有相同的方法和属性
        action的名字(context, 载荷) {
            // 1. 发异步请求,请求数据
            // 2. commit 调用mutation 来修改数据
            // 3. context.commit('mutation名', 载荷)
        }
    }
})

调用格式:

  1. 直接使用: 在组件中通过 this.$store.dispatch('actions的名字',参数)来调用action。
  2. 还可以基于 Vuex 提供的 mapActions 辅助函数,可以方便的把 Store 中指定的Action,映射为当前组件的 methods:

map辅助函数:

methods: {

​ ...mapActions(['actions名'],...mapActions({'新名字':'actions名'}))

}

小结:

​ action一般用来发异步请求,数据回来之后,再去调用mutations来保存数据。

将ajax请求放在 actions 中有两个好处:

  1. 代码得到了进一步封装。将发ajax和保存数据到vue绑定在一起。
  2. 逻辑更通顺。如果数据需要保存在vuex的state中,那么从接口处获取数据的操作就定义在Vuex的actions中。

Vuex-用modules来拆分复杂业务

问题导入:

​ 所有的全局数据、方法都集中到了一起,导致Vuex的结构混乱,不利于现阶段的开发和后期的维护。

modules的作用

拆分模板,把复杂的场景按模块来拆开。

export default new Vuex.Store({
    // state: 用来保存所有的公共数据
    state: {},
    getters: {},
    mutatios: {},
    actions: {},
    modules: {
        模块名1: {
            // namespaced 为 true ,则在使用mutations 时,就必须要加上模块名
            namespaced: true,
            state: {},
            getters: {},
            mutations: {},
            actions: {},
            modules: {}
        },
        模块名2: {
            // namespaced 不写,默认为false,则在使用mutations
            时,不需要加模块名
            state: {},
            getters: {},
        	mutations:{},
        	actions: {},
        	modules:{}
        },
    }
})

也可对文件进一步拆分

|--store /
|------- index.js # 引入模块
|------- modules
|-------------- / mod1.js # 模块1
|-------------- / mod2.js # 模块2

访问数据和修改数据的调整

  • 访问模块中的数据,要加上模块名
获取数据项:  {{$store.state.模块名.数据项名}}
获取getters: {{$store.getters['模块名/getters名']}}

访问模块中的mutations/actions:

  • 如果namespaced为true,则需要额外去补充模块名
  • 如果namespaced为false,则不需要额外补充模块名
$store.commit('mutations名')        // namespaced为false
$store.commit('模块名/mutations名')  // namespaced为true

小结

使用了modules之后,在访问数据时就要额外添加modules的名字了。

结论: 在使用modules时,建议都给加上namespaced!