vuex 的使用

用于多组件共享状态,如果不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果应用够简单,您最好不要使用 Vuex。可使用简单Bus总线的方式来管理共享的数据详见(http://www.cnblogs.com/fanlinqiang/p/7756566.html)。但是,如果您需要构建是一个中大型单页应用,vuex可以更好地在组件外部管理状态

引入:

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import createLogger from 'vuex/dist/logger'

Vue.use(Vuex)


const store = new Vuex.Store({
      plugins: [createLogger()],
      state: {
        count: 0,
        todos: [
          { id: 1, text: '...', done: true },
          { id: 2, text: '...', done: false }
        ]
      },
      getters: {
        doneTodos: state => {
          return state.todos.filter(todo => todo.done)
        },
        doneTodosCount: (state, getters) => { //注:Getter 也可以接受其他 getter 作为第二个参数
            return getters.doneTodos.length
        },
        getTodoById: (state) => (id) => { //getter 返回一个函数来实现给 getter 传参
            return state.todos.find(todo => todo.id === id)
        }
      },
      mutations: { //mutation 必须同步执行,为解决这个问题我们引入了action
       increment (state, payload) { //store.commit 传入额外的参数,即 mutation 的 载荷(payload)         
             state.count += payload.amount
          }
      },
      actions: {
        //Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,
        //因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。
        increment (context) {
          context.commit('increment')
        },
        increment ({ commit }) { //es6解构
            commit('increment')
        },
        incrementAsync ({ commit }) {
            setTimeout(() => {
              commit('increment')
            }, 1000)
        },
        //store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise
        actionA ({ commit }) {
            return new Promise((resolve, reject) => {
              setTimeout(() => {
                commit('someMutation')
                resolve()
              }, 1000)
            })
          },
        actionB ({ dispatch, commit }) {
            return dispatch('actionA').then(() => {
              commit('someOtherMutation')
            })
          }
        // 假设 getData() 和 getOtherData() 返回的是 Promise
        async actionA ({ commit }) {
            commit('gotData', await getData())
          },
        async actionB ({ dispatch, commit }) {
            await dispatch('actionA') // 等待 actionA 完成
            commit('gotOtherData', await getOtherData())
         }
      }
})

export default store

最好提前在你的 store 中初始化好所有所需属性。当需要在对象上添加新属性时,你应该使用 Vue.set(obj, 'newProp', 123), 或者
以新对象替换老对象。例如,利用 stage-3 的对象展开运算符我们可以这样写:

state.obj = { ...state.obj, newProp: 123 }

 组件a:

import { mapState, mapActions, mapMutations } from 'vuex'

export default {
    data() {
        return {
      localCount: 2
    } }, methods:{ getTodoById(id) {
return this.$store.getters.getTodoById(id) }, increment(payload){ //payload可以为对象,如:{ amount: 10} this.$store.commit('increment', payload) //对象风格的提交方式 //this.$store.commit({type: 'increment',amount: 10}) }, ...mapMutations([ //mutation 都是同步事务,store.commit('increment'), 任何由 "increment" 导致的状态变更都应该在此刻完成。 //为解决异步问题我们引入action 'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')` //add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')` // `mapMutations` 也支持载荷: 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)` ]), ...mapActions([ 'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')` //add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')` // `mapActions` 也支持载荷: 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)` ]), actionA() { store.dispatch('actionA').then(() => { // ... }) } }, computed:{ //count () { // return this.$store.state.count //} ...mapState({ // 使用对象展开运算符将此对象混入到外部对象中 // 箭头函数可使代码更简练 count: state => state.count, // 传字符串参数 'count' 等同于 `state => state.count` countAlias: 'count', // 为了能够使用 `this` 获取局部状态,必须使用常规函数 countPlusLocalState (state) { return state.count + this.localCount } }), doneTodosCount () { return this.$store.state.todos.filter(todo => todo.done).length }, DoneTodos(){ return this.$store.getters.doneTodos }, getDoneTodosCount () { return this.$store.getters.doneTodosCount }, // 使用对象展开运算符将 getter 混入 computed 对象中 ...mapGetters([ 'doneTodosCount', //映射 `this.doneCount` 为 `store.getters.doneTodosCount` doneCount: 'doneTodosCount' ]) } }

main.js

import Vue from 'vue'
import store from './store/'

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

使用常量替代 Mutation 事件类型

使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 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
    }
  }
})

Mutation 必须是同步函数

一条重要的原则就是要记住 mutation 必须是同步函数。为什么?请参考下面的例子:

mutations: {
  someMutation (state) {
    api.callAsyncMethod(() => {
      state.count++
    })
  }
}

现在想象,我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的的状态的改变都是不可追踪的。

Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

  1. 应用层级的状态应该集中到单个 store 对象中。

  2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。

  3. 异步逻辑都应该封装到 action 里面。

只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。

对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API请求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── cart.js       # 购物车模块
        └── products.js   # 产品模块

 modules:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

 为什么使用getters来访问数据?

访问state中数据直接使用this.$store.state.elements是可以的,但根据业务的需求往往还要做一些业务上的处理,如:state中goods存放的是用户购买的清单,但此时我们只需要商品的数量,我们不需要拿到所有的物品清单,此时我们就可以在获得state的过程中在加上一层逻辑,也就是getters来获得物品数量

 vuex存取的数据,在刷新页面时丢失?

 将数据存入cookie,webstorage,当刷新页面时判断是否有数据,没有再去取

原文地址:https://www.cnblogs.com/fanlinqiang/p/8007317.html