vuex 实战了解这些就够了

目录

 

一. 安装

1.1. 加入依赖

1.2. 项目中引入

1.3. 示例

main.js

store.js

flightInfo.js(模块化状态管理)

type.js(mutations名称常量化)

二.  用法

2.1. state

2.1.1. 定义state

2.1.2. 导入state

2.2. Getter

2.2.1. 定义getter

2.2.2. 导入getter

2.3. Mutation

2.3.1. 定义mutation

2.3.2. 触发mutation

2.3.3. 触发时携带参数

2.3.4. 使用常量定义 Mutation 事件类型

2.3.5. Mutation 必须是同步函数

2.4. Action

2.4.1. 注册 action

2.4.2. 分发 Action


一. 安装

1.1. 加入依赖

npm install vuex --save

  Vuex 依赖 Promise。如果你支持的浏览器并没有实现 Promise,那么你可以使用一个 polyfill 的库,例如 es6-promise

npm install es6-promise --save

1.2. 项目中引入

以最新的vue-cli3架构为例,在src/main.js中加入

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

Vue.use(Vuex)

更普遍的,一般是有一个专门的状态管理js文件,如store.js

在main.js中只是引入store.js。而在store.js中加入上述引用部分。以后相关状态管理都是store.js中去做的。

1.3. 示例

先贴实战部分示例来了解一下直观的用法

main.js

参考《vue-router 实战了解这些就够了》一文中 main.js 部分

store.js

import Vue from 'vue'
import Vuex from 'vuex'
import flightInfo from './modules/flightInfo'
Vue.use(Vuex)

export default new Vuex.Store({

  modules: {
    flightInfo
  },
  state: {

  },
  mutations: {

  },
  actions: {

  }
})

flightInfo.js(模块化状态管理)

import * as types from '../type'

const state = {
  flightInfo: []
}

const getters = {
  getflightInfo: state => state.flightInfo
}

const actions = {
  saveFlightInfo ({ commit }, data) {
    return new Promise(resolve => {
      commit(types.FLIGHTINFO, data)
      resolve(data)
    })
  }
}

const mutations = {
  [types.FLIGHTINFO] (state, data) {
    state.flightInfo = data
    localStorage.setItem('flightInfo', JSON.stringify(state.flightInfo))
  }
}

export default {
  state,
  actions,
  getters,
  mutations
}

type.js(mutations名称常量化)

export const FLIGHTINFO = 'FLIGHTINFO'

以上涉及各js文件的目录组织如下:

src

------ main.js

------ store

------------ store.js

------------ type.js

------------ module

------------------ flightInfo.js

 

二.  用法

vuex状态管理原理

2.1. state

Vuex 使用单一状态树,这也意味着,每个应用将仅仅包含一个 store 实例。

2.1.1. 定义state

const store = new Vuex.Store({
  state: {
    count: 0
  }
})

2.1.2. 导入state

  • 方式1:计算属性(store对象单独导入)

由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态:

const Counter = {
  template: `<div>{
   
   { count }}</div>`,
  computed: {
    count () {
      return store.state.count
    }
  }
}

缺点:每个需要使用 state 的组件中都需要需要频繁地导入store

  • 方式2:计算属性 (store对象全局导入)

Vuex 通过 store 选项,提供了一种机制将状态从根组件 注入 到每一个子组件中(需调用 Vue.use(Vuex)):

const app = new Vue({
  el: '#app',
  // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})

通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。让我们更新下 Counter 的实现:

const Counter = {
  template: `<div>{
   
   { count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}

缺点:当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。 

  • 方式3: mapState 辅助函数 (store对象全局导入)
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

import { mapState } from 'vuex';

const store = new Vuex.Store({
    state: {
        count: 3
    }
});
new Vue({ 
    el: '#app',
    store,
    data() {
        return {
            localCount: 4
        }
    },
    computed: mapState({
        count: state => state.count,
        // 传字符串参数 'count' 等同于 `state => state.count`
        countAlias: 'count',
        // 为了能够使用 `this` 获取局部状态,必须使用常规函数(相对于箭头函数)
        countPlusLocalState (state) {
            return state.count + this.localCount
        }
    })
});

当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。

computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
])

方式4: mapState 辅助函数 + 对象展开符(store对象全局导入)

mapState 函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢?

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

2.2. Getter

有时候我们需要从 store 中的 state 中派生出一些状态?

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

2.2.1. 定义getter

Getter 接受 state 作为其第一个参数:

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

Getter 也可以接受其他 getter 作为第二个参数:

getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}

2.2.2. 导入getter

1. 通过属性

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

方式1:单独引入store对象(通过 import 引入store.js)

store.getters.doneTodos

方式2:全局注入store对象(通过Vue中store选项)

computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}

2. 通过方法

方式3

通过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。

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

注意,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。

方式4: mapGetters 辅助函数 + 对象展开符(store对象全局导入)

mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:

import { mapGetters } from 'vuex'

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

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

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

2.3. Mutation

2.3.1. 定义mutation

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

2.3.2. 触发mutation

方式1

store.commit('increment')

方式2: mapMutations 辅助函数 + 对象展开符 + store对象全局导入

mport { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
      // `mapMutations` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }
}

 

2.3.3. 触发时携带参数

参数为原始类型

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

参数为对象类型

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

2.3.4. 使用常量定义 Mutation 事件类型

// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'

const store = new Vuex.Store({
  state: { ... },
  mutations: {
    // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
    [SOME_MUTATION] (state) {
      // mutate state
    }
  }
})

2.3.5. Mutation 必须是同步函数

 

2.4. Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

2.4.1. 注册 action

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

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

用ES2015 的 参数解构 来简化代码(特别是我们需要调用 commit 很多次的时候):

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}

2.4.2. 分发 Action

方式1:store对象单独导入 + 无负载

store.dispatch('increment')

 方式2:store对象单独导入 + 负载

store.dispatch('incrementAsync', {amount: 10})

方式3:store对象全局导入 + 负载

this.$store.dispatch('incrementAsync', {amount: 10})

方式4: mapActions 辅助函数 + 对象展开符 + store对象全局导入

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}

猜你喜欢

转载自blog.csdn.net/u014225733/article/details/95334034