zoukankan      html  css  js  c++  java
  • 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,当刷新页面时判断是否有数据,没有再去取

  • 相关阅读:
    Ubuntu 18.04.3 更改系统语言为简体中文
    Centos7.3、nginx环境下部署hugo博客
    Centos7.3 卸载 Nginx(彻底卸载) 并重新安装 Nginx(RPM源yum安装)
    Centos7.3、nginx环境下部署hexo博客(非git推送方式)
    使用阿里云对象存储OSS+PicGo搭建图床
    Hexo博客添加LiveRe评论系统
    使用 jsDelivr CDN加速Github 仓库的图片
    解决win10一开机占用内存就飙到70%的问题
    [Andriod官方训练教程]管理Activity的生命活动之停止和重启一个Activity
    [Andriod官方训练教程]支持不同的设备之支持不同的语言
  • 原文地址:https://www.cnblogs.com/fanlinqiang/p/8007317.html
Copyright © 2011-2022 走看看