vuex

111 阅读1分钟

⭐⭐组件单向数据流

image.png

为什么需要抽取状态组成vuex

1.对于嵌套太多层组件需要共享里面的状态数据,需要太繁琐的操作,并且对于兄弟组件之间状态数据共享也无能为力的情况下

2.我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。

⭐⭐state

可以同过this.$store.state.valName进行访问

mapState辅助函数

1.普通写法

import { mapState } from 'vuex';

export default{
    computed:mapState({
        // 1
        count: state=> state.count,
        // 2 传字符串参数‘count’,等于state=>state.count
        countAlios:'count',
        // 3 为了能够使用 `this` 获取局部状态,必须使用常规函数
        countPlusLocalState (state) {
              return state.count + this.localCount
        }
    })
}

2.字符串数组

// 也可以给计算属性传递一个字符串数组
computed:mapState([
    // 映射count 为store,state.count
    'count'
])

3.对象展开运算符

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

⭐⭐getter(state的计算属性)

第一个参数state和getters

getter:{
    countGetter(state,getters){
        return getters.count.length
    }
}

通过方法访问实现Getter传参
getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
store.getters.getTodoById(2)
访问方式

1.

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

2.mapGetters 辅助函数

import { mapGetters } from 'vuex'

export default{
    computed:{
    // 解构数组
        ...mapGetters([
            'countGetter',
            'anyGetter'
        ]),
        // 使用对象解构方法,可以重命名getter
        ...mapGetters({
            // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
            doneCount:'doneTodosCount'
        })
    }
}

⭐⭐mutation

mutation接受两个参数state和payload(载荷)

提交载荷

1.普通提交

mutation:{
    increation(state,payload){
        state.count += payload
    }
}
this.$store.commit('increation',10)

2.对象提交风格方式

this.$store.commit({
    type:'increation',
    amount:10
})
mutation:{
    increation(state,payload){
        state.count += payload.amount
    }
}
多人协作可以使用常量替代 Mutation 事件类型

使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:

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

const store = createStore({
  state: { ... },
  mutations: {
    // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
    [SOME_MUTATION] (state) {
      // 修改 state
    }
  }
})
mutation必须是同步函数

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

mapMutations
import { 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')`
    })
  }
}

⭐⭐action

action 接受第一个context上下文这个对象可以解构出useState、state、commit、getters第二个参数是payload

在组件里面触发
// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})
mapActions
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')`
    })
  }
}

⭐⭐module

模块的局部状态

模块中action和getters都接受rootState根节点状态值,通过这个值可以去访问根节点state值

命名空间

可以通过设置namespaced:true来区分不同模块,模块中下state,getters,mutation,action都会根据模块自动注册的路径调整命名.

若需要在全局命名空间分发action或提交mutation,将{root:true}作为第三参数传给dispatch或commit即可。

modules: {
  foo: {
    namespaced: true,

    getters: {
      // 在这个模块的 getter 中,`getters` 被局部化了
      // 你可以使用 getter 的第四个参数来调用 `rootGetters`
      someGetter (state, getters, rootState, rootGetters) {
        getters.someOtherGetter // -> 'foo/someOtherGetter'
        rootGetters.someOtherGetter // -> 'someOtherGetter'
      },
      someOtherGetter: state => { ... }
    },

    actions: {
      // 在这个模块中, dispatch 和 commit 也被局部化了
      // 他们可以接受 `root` 属性以访问根 dispatch 或 commit
      someAction ({ dispatch, commit, getters, rootGetters }) {
        getters.someGetter // -> 'foo/someGetter'
        rootGetters.someGetter // -> 'someGetter'

        dispatch('someOtherAction') // -> 'foo/someOtherAction'
        dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'

        commit('someMutation') // -> 'foo/someMutation'
        commit('someMutation', null, { root: true }) // -> 'someMutation'
      },
      someOtherAction (ctx, payload) { ... }
    }
  }
}
若需要在带命名空间的模块注册全局action
{
  actions: {
    someOtherAction ({dispatch}) {
      dispatch('someAction')
    }
  },
  modules: {
    foo: {
      namespaced: true,

      actions: {
        someAction: {
          root: true,
          handler (namespacedContext, payload) { ... } // -> 'someAction'
        }
      }
    }
  }
}
在带命名空间的绑定函数map
computed: {
  ...mapState({
    a: state => state.some.nested.module.a,
    b: state => state.some.nested.module.b
  })
},
methods: {
  ...mapActions([
    'some/nested/module/foo', // -> this['some/nested/module/foo']()
    'some/nested/module/bar' // -> this['some/nested/module/bar']()
  ])
}
computed: {
  ...mapState('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module', [
    'foo', // -> this.foo()
    'bar' // -> this.bar()
  ])
}

还可以通过createNamespacedHelpers来创建基于某个命名空间辅助函数,它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数:

import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')

export default {
  computed: {
    // 在 `some/nested/module` 中查找
    ...mapState({
      a: state => state.a,
      b: state => state.b
    })
  },
  methods: {
    // 在 `some/nested/module` 中查找
    ...mapActions([
      'foo',
      'bar'
    ])
  }
}

严格模式

开启严格模式,仅需在创建 store 的时候传入 strict: true,严格模式下state改变必须由mutation函数引起的,否则将抛出错误。

const store = createStore({
  // ...
  strict: true
})

开发环境与发布环境

不要在发布环境下启用严格模式,严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式,以避免性能损失

const store = createStore({
  // ...
  strict: process.env.NODE_ENV !== 'production'
})

表单双向表单,严格模式下不允许直接修改,所以需要一些特殊手法

<input v-model="obj.message">

修改为

<input :value="message" @input="updateMessage">


// ...
computed: {
  ...mapState({
    message: state => state.obj.message
  })
},
methods: {
  updateMessage (e) {
    this.$store.commit('updateMessage', e.target.value)
  }
}
<input v-model="message">


computed: {
  message: {
    get () {
      return this.$store.state.obj.message
    },
    set (value) {
      this.$store.commit('updateMessage', value)
    }
  }
}