阿里云主机折上折
  • 微信号
Current Site:Index > Options-style Store writing

Options-style Store writing

Author:Chuan Chen 阅读数:34956人阅读 分类: Vue.js

Options-style Store Writing

The Options-style Store is the traditional state management approach in Vuex, organizing the store by defining an object containing options such as state, mutations, and actions. This method offers a clear structure and is suitable for small to medium-sized projects or developers new to Vuex.

Basic Structure

A complete Options-style Store typically includes the following core parts:

const store = new Vuex.Store({
  state: {},       // State data
  getters: {},     // Computed properties
  mutations: {},   // Synchronous state modifications
  actions: {},     // Asynchronous operations
  modules: {}      // Modularization
})

State Definition

State is where the application's state is stored. It is recommended to centralize all shared data:

state: {
  user: {
    name: 'Zhang San',
    age: 28,
    token: 'abc123'
  },
  products: [
    { id: 1, name: 'Product A', price: 100 },
    { id: 2, name: 'Product B', price: 200 }
  ],
  loading: false
}

Mutations Usage

Mutations are the only way to directly modify the state and must be synchronous functions:

mutations: {
  // Basic usage
  SET_LOADING(state, payload) {
    state.loading = payload
  },
  
  // Object-style commit
  UPDATE_USER(state, { key, value }) {
    state.user[key] = value
  },
  
  // Array operation example
  ADD_PRODUCT(state, product) {
    state.products.push(product)
  },
  
  // Using constants as function names
  [INCREMENT_AGE](state) {
    state.user.age++
  }
}

Actions for Asynchronous Handling

Actions are used for asynchronous operations and ultimately modify the state by committing mutations:

actions: {
  // Basic asynchronous operation
  async fetchUser({ commit }, userId) {
    commit('SET_LOADING', true)
    try {
      const user = await api.getUser(userId)
      commit('SET_USER', user)
    } catch (error) {
      commit('SET_ERROR', error.message)
    } finally {
      commit('SET_LOADING', false)
    }
  },
  
  // Combining multiple actions
  async initApp({ dispatch }) {
    await dispatch('fetchUser')
    await dispatch('fetchProducts')
  }
}

Getters as Computed Properties

Getters can be considered computed properties of the store and are suitable for derived state:

getters: {
  // Basic getter
  totalPrice: state => {
    return state.products.reduce((sum, product) => sum + product.price, 0)
  },
  
  // Getter returning a function
  getProductById: state => id => {
    return state.products.find(product => product.id === id)
  },
  
  // Using other getters
  discountedProducts: (state, getters) => {
    return state.products.map(product => ({
      ...product,
      discountPrice: product.price * 0.9
    }))
  }
}

Modular Organization

When the application grows, the store can be split into modules:

const userModule = {
  namespaced: true,
  state: () => ({
    profile: null
  }),
  mutations: {
    SET_PROFILE(state, profile) {
      state.profile = profile
    }
  }
}

const productModule = {
  namespaced: true,
  state: () => ({
    list: []
  }),
  actions: {
    loadAll({ commit }) {
      // ...
    }
  }
}

const store = new Vuex.Store({
  modules: {
    user: userModule,
    product: productModule
  }
})

Strict Mode

Enable strict mode in development to prevent direct state modifications:

const store = new Vuex.Store({
  strict: process.env.NODE_ENV !== 'production',
  // ...other configurations
})

Plugin Development

Extend store functionality with plugins, such as a persistence plugin:

const persistPlugin = store => {
  // Restore state from local storage on initialization
  const savedState = localStorage.getItem('vuex-state')
  if (savedState) {
    store.replaceState(JSON.parse(savedState))
  }
  
  // Subscribe to mutation changes
  store.subscribe((mutation, state) => {
    localStorage.setItem('vuex-state', JSON.stringify(state))
  })
}

const store = new Vuex.Store({
  plugins: [persistPlugin],
  // ...other configurations
})

Integration with Components

Use mapHelpers in components to simplify store access:

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

export default {
  computed: {
    // Array syntax
    ...mapState(['user', 'products']),
    
    // Object syntax
    ...mapState({
      userName: state => state.user.name,
      firstProduct: state => state.products[0]
    }),
    
    // Getters mapping
    ...mapGetters(['totalPrice', 'discountedProducts'])
  },
  
  methods: {
    // Actions mapping
    ...mapActions(['fetchUser', 'initApp']),
    
    // Namespaced actions
    ...mapActions('user', ['updateProfile'])
  }
}

Form Handling

Handling two-way binding for forms in Vuex:

export default {
  data() {
    return {
      localUser: {}
    }
  },
  
  created() {
    // Copy state to local data on initialization
    this.localUser = { ...this.$store.state.user }
  },
  
  methods: {
    updateUser() {
      // Update state on submission
      this.$store.commit('UPDATE_USER', this.localUser)
    }
  }
}

Testing Related

Writing testable store code:

// Export options separately for testing
export const storeOptions = {
  state: { count: 0 },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  actions: {
    asyncIncrement({ commit }) {
      setTimeout(() => {
        commit('increment')
      }, 100)
    }
  }
}

// Test example
describe('store', () => {
  it('increment mutation', () => {
    const state = { count: 0 }
    storeOptions.mutations.increment(state)
    expect(state.count).toBe(1)
  })
})

Type Hints

Adding TypeScript support for Options-style Store:

interface State {
  user: {
    name: string
    age: number
  }
  products: Array<{
    id: number
    name: string
    price: number
  }>
}

const store = new Vuex.Store<State>({
  state: {
    user: {
      name: '',
      age: 0
    },
    products: []
  },
  mutations: {
    SET_USER(state: State, payload: State['user']) {
      state.user = payload
    }
  }
})

Performance Optimization

Techniques for optimizing Options-style Store in large applications:

const store = new Vuex.Store({
  // Use a function to return the state object to avoid shared references between modules
  state: () => ({
    largeData: null
  }),
  
  // Lazy registration of dynamic modules
  modules: {
    bigModule: {
      namespaced: true,
      // Dynamically import module definition
      ...import('./big-module')
    }
  }
})

Common Patterns

Common design patterns in Options-style Store:

const store = new Vuex.Store({
  // State grouping
  state: {
    ui: {
      loading: false,
      theme: 'light'
    },
    data: {
      users: [],
      products: []
    }
  },
  
  // Factory function to create modules
  modules: {
    dynamicModule: createDynamicModule()
  }
})

function createDynamicModule() {
  return {
    state: () => ({ value: 0 }),
    mutations: {
      increment(state) {
        state.value++
      }
    }
  }
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:组合式Store写法

下一篇:Store间相互调用

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.