VueJS: Module

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Do sử dụng một cây trạng thái duy nhất, tất cả trạng thái của ứng dụng của ta được chứa bên trong một đối tượng lớn. Tuy nhiên, khi ứng dụng của ta phát triển theo quy mô, store có thể thực sự cồng kềnh.

Để khắc phục điều đó, Vuex cho phép ta chia store của mình thành các mô-đun. Mỗi mô-đun có thể chứa state, mutations, actions, getters và thậm chí chứa cả các mô-đun khác:

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`'s state
store.state.b // -> `moduleB`'s state

Module state cục bộ

Bên trong các mutations và getters của mô-đun, đối số đầu tiên nhận được sẽ là state cục bộ của mô-đun.

const moduleA = {
  state: { count: 0 },
  mutations: {
    increment (state) {
      // 'state' là state module cục bộ
      state.count++
    }
  },

  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  }
}

Tương tự, bên trong các actions của mô-đun, context.state sẽ hiển thị state cục bộ và state root sẽ được hiển thị dưới dạng context.rootState:

const moduleA = {
  // ...
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

Ngoài ra, bên trong getters của module, state root sẽ được hiển thị ở đối số thứ 3:

const moduleA = {
  // ...
  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }
}

Namespacing

Theo mặc định thì actions, mutations và getters bên trong mô-đun vẫn được đăng ký theo không gian tên chung - điều này cho phép nhiều mô-đun phản ứng với cùng một loại mutations/actions.

Nếu bạn muốn mô-đun của mình được tự chứa hoặc sử dụng lại nhiều hơn, bạn có thể đánh dấu mô-đun là không gian tên namespaced: true. Khi module được đăng ký, tất cả các getters, actions và mutations của nó sẽ tự động được đặt tên dựa trên đường dẫn mà module được đăng ký. Ví dụ:

const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,

      // module asset
      state: { ... }, // state của module hoàn toàn được lồng và không bị ảnh hưởng bởi tùy chọn namespace
      getters: {
        isAdmin () { ... } // -> getters['account/isAdmin']
      },
      actions: {
        login () { ... } // -> dispatch('account/login')
      },
      mutations: {
        login () { ... } // -> commit('account/login')
      },

      // module lồng
      modules: {
        // inherits the namespace from parent module
        myPage: {
          state: { ... },
          getters: {
            profile () { ... } // -> getters['account/profile']
          }
        },

        // further nest the namespace
        posts: {
          namespaced: true,

          state: { ... },
          getters: {
            popular () { ... } // -> getters['account/posts/popular']
          }
        }
      }
    }
  }
})

getters và actions namespace sẽ được local hóa gettersdispatch và commit. Nói cách khác, bạn có thể sử dụng các phần tử mô-đun mà không cần viết tiền tố trong cùng một mô-đun. Chuyển đổi giữa các không gian tên không ảnh hưởng đến mã bên trong mô-đun.

#Truy cập nội dung global trong các mô-đun không gian tên

Nếu bạn muốn sử dụng states global và getters, rootState và rootGetters được truyền như các đối số thứ 3 và thứ 4 cho các hàm getter, và cũng được hiển thị như các thuộc tính trên đối tượng context được truyền cho các hàm action.

Để gửi các actions hoặc thực hiện các mutations trong không gian tên chung, hãy chuyển { root: true } làm đối số thứ 3 đến dispatch và commit.

modules: {
  foo: {
    namespaced: true,

    getters: {
      // `getters` được cục bộ hóa cho các getters của module này
      // bạn có thể sử dụng rootGetters qua đối số thứ 4 của getters
      someGetter (state, getters, rootState, rootGetters) {
        getters.someOtherGetter // -> 'foo/someOtherGetter'
        rootGetters.someOtherGetter // -> 'someOtherGetter'
      },
      someOtherGetter: state => { ... }
    },

    actions: {
      // dispatch và commit cũng được cục bộ hóa cho module này
      // chúng sẽ chấp nhận tùy chọn `root` cho 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) { ... }
    }
  }
}

#Đăng ký global action trong Mô-đun không gian tên

Nếu bạn muốn đăng ký các global actions trong các mô-đun không gian tên, bạn có thể đánh dấu nó bằng root: true và đặt định nghĩa bộ xử lý action trong actions. Ví dụ:

{
  actions: {
    someOtherAction ({dispatch}) {
      dispatch('someAction')
    }
  },
  modules: {
    foo: {
      namespaced: true,

      actions: {
        someAction: {
          root: true,
          handler (namespacedContext, payload) { ... } // -> 'someAction'
        }
      }
    }
  }
}

#Ràng buộc Helper với không gian tên

Khi gắn một module namespaced với các component với các helper mapStatemapGettersmapActions và mapMutations, nó có thể nhận được một chút chi tiết:

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']()
  ])
}

Trong những trường hợp như vậy, bạn có thể truyền chuỗi không gian tên mô-đun làm đối số đầu tiên cho helper để tất cả các ràng buộc được thực hiện bằng cách sử dụng mô-đun đó làm ngữ cảnh. Đoạn code trên có thể được đơn giản hóa thành:

computed: {
  ...mapState('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module', [
    'foo', // -> this.foo()
    'bar' // -> this.bar()
  ])
}

Hơn nữa, bạn có thể tạo helper không gian tên bằng cách sử dụng createNamespacedHelpers. Nó trả về một đối tượng có các helper ràng buộc component mới được ràng buộc với giá trị không gian tên đã cho:

import { createNamespacedHelpers } from 'vuex'

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

export default {
  computed: {
    // hãy để ý `some/nested/module`
    ...mapState({
      a: state => state.a,
      b: state => state.b
    })
  },
  methods: {
    // hãy để ý `some/nested/module`
    ...mapActions([
      'foo',
      'bar'
    ])
  }
}

Caveat dành cho nhà phát triển plugin

Bạn có thể quan tâm đến việc đặt tên không thể đoán trước cho các mô-đun của bạn khi bạn tạo một plugin cung cấp các mô-đun và cho phép người dùng thêm chúng vào store Vuex. Mô-đun của bạn cũng sẽ được đặt tên nếu người dùng plugin thêm mô-đun của bạn trong mô-đun không gian tên. Để điều chỉnh tình huống này, bạn có thể cần nhận được một giá trị không gian tên thông qua tùy chọn plugin của bạn:

// lấy giá trị namespace qua tùy chọn plugin
// và trả về function plugin Vuex
export function createPlugin (options = {}) {
  return function (store) {
    // và namespace tới các type của module plugin
    const namespace = options.namespace || ''
    store.dispatch(namespace + 'pluginAction')
  }
}

Đăng ký mô-đun động

Bạn có thể đăng ký một mô-đun sau khi store đã được tạo bằng phương thức store.registerModule:

// đăng ký module `myModule`
store.registerModule('myModule', {
  // ...
})

// đăng ký module lồng `nested/myModule`
store.registerModule(['nested', 'myModule'], {
  // ...
})

state của mô-đun sẽ được hiển thị dưới dạng store.state.myModule và store.state.nested.myModule.

Đăng ký mô-đun động làm cho nó có thể cho các plugin Vue khác cũng tận dụng Vuex cho quản lý state bằng cách gắn một mô-đun vào kho ứng dụng. Ví dụ: thư viện vuex-router-sync tích hợp router vue với vuex bằng cách quản lý route state của ứng dụng trong mô-đun được đính kèm động.

Bạn cũng có thể loại bỏ một mô-đun đăng ký động bằng store.unregisterModule(moduleName). Lưu ý rằng bạn không thể loại bỏ các mô-đun tĩnh (khai báo tại store) bằng cách thức này.

Có thể bạn muốn giữ state trước đó khi đăng ký một mô-đun mới, chẳng hạn như bảo toàn state từ ứng dụng Máy chủ được hiển thị. Bạn có thể đạt được điều này với tùy chọn preserveState:store.registerModule('a', module, { preserveState: true })

Mô-đun tái sử dụng

Đôi khi, chúng ta có thể cần phải tạo nhiều phiên bản của một mô-đun, ví dụ:

  • Tạo nhiều store sử dụng cùng một mô-đun (ví dụ: Để tránh các trình đơn trạng thái trong SSR khi tùy chọn runInNewContext là false hoặc 'once');
  • Đăng ký cùng một mô-đun nhiều lần trong cùng một store.

Nếu ta sử dụng một đối tượng đơn giản để khai báo state của mô-đun, thì đối tượng state đó sẽ được chia sẻ bằng tham chiếu và gây nhiễu loạn state store/mô-đun khi nó được mutation.

Đây thực sự là vấn đề với component data bên trong Vue. Vì vậy, giải pháp cũng giống nhau - sử dụng một hàm để khai báo state mô-đun (được hỗ trợ trong 2.3.0+):

const MyReusableModule = {
  state () {
    return {
      foo: 'bar'
    }
  },
  // mutations, actions, getters...
}
» Tiếp: Cấu trúc ứng dụng
« Trước: Action
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!