vuex4


vuex-4

起始

  • vue4是为vue3做的适配,vue2用低于vue4版本的
  • vuex Stores 是具有响应性的,state的更新是有效且及时的
  • state是不能直接改变的,需要提交mutations,留下记录。
import {createApp} from 'vue'
import {createStore} from 'vuex'

const store = createStore({
    state () {
        return {
            count: 0
        }
    },
    mutations: {
        increment (state) {
            state.count++
        }
    }
})
const app = createApp({})
app.use(store)

通过store.state.count或this.\(store.state.count获取值,store.commit('increment')或this.\)store.commit('increment')更改state

核心观点

state

  • vuex使用单一声明树,与data具有相同的规则
  • 可通过计算属性获取state的值
const Counter = {
    template: `<div>{{count}}</div>`,
    computed: {
        count() {
            // this.$store.state.count
            return store.state.count
        }
    } 
}
  • mapState能同时获得多个state属性
import {mapState} from 'vuex'
export default {
 computed: mapState({
    count: state => state.count,
    // 同上获取值
    countAlias: 'count',
    // 将state值转换为this的函数
    countPlusLocalState (state) {
    return state.count + this.localCount
}
})
}

当state中的属性名称和计算属性名称相同时,可用字符串数组接收

computed: mapState(['count'])

同其他计算属性混合在一起时需用到对象传播符...

computed: {
localComputed(){},
...mapState({})
}

Getter

  • stores的计算属性
  • 对state中的属性进行处理
const store = createStore({
 state: {
        todos: [
            {id: 1, text: '', done: true},
            {id:2 ,text: '', done: false}
        ]
    },
 getters: {
        doneTodos (state) {
            return state,todos.filter(todo => todo.done)
        }
    }
})
  • 获取属性值store.getters.doneTodos
  • getters可接受其他getters作为第二个参数
  • 以一个函数作为参数
getters: {
 getTodoById: (state) => (id) => {
        return state.todo.find(todo => todo.id === id)
    }
}
  • mapGetters 简单的映射成为本地计算属性
import {mapGetters} from 'vuex'
export default {
    computed: {
        ...mapGetters(['doneTodosCount','anotherGetter'])
//      ...mapGetters({doneCount: 'doneTodosCount'})
    }
}

Mutations

  • 对state中的属性进行更新,以state作为第一个参数
  • 通过store.commit进行提交,执行该方法
  • commit中的负载参数作为mutations的第二个参数
  • commit的一个可替换方法
store.commit({
    type: 'increnment',
    amount: 10
})
mutations: {
    increment(state,payload){
        state.count += payload.amount
    }
}
  • 以一个常量作为函数名
mutations: {
    [SOME_MUTATION] (state) {}
}
  • 其内的函数必须是同步的
  • mapMutations帮助store.commit与组件内的方法进行映射
import {mapMutations} from 'vuex'

export default{
    methods: {
        // map `this.increment()` to `this.$store.commit('increment')`
        // `mapMutations` also supports payloads:
        // map `this.incrementBy(amount)` to `this.$store.commit('incrementBy', amount)`
        ...mapMutations(['increment','incrementBy']),
        ...mapMutations({
        add: 'increment'
        })
    }
}

Actions

  • 代替Mutations,在actions可提交Mutations
  • actions可执行异步操作,其触发方法store.dispatch
  • context.commit、context.state、context.getters、其他的actions的context.dispatch
actions: {
    increment(context) {
    context.commit('increment')
},
increment ({commit}) {
commit('increment')
}
}

负载参数

actions: {
    incrementAsync({commit}){
        setTimeout(() => {
    commit('increment')
        },1000)
    }
}
store.dispatch('incrementAsync', {
        amount:10
    })
store.dispatch({
    type:'incrementAsync',
    amount:10
})
actions: {
    checkout({commit, state}, products) {
        const saveCardItems = [...state.card.added]
        commit(types.CHECKOUT_REQUEST)
        shop.buyProducts(
        products,
        // 捕获成功
        () => commit(types.CHECKOUT_SUCCESS),
        //捕获失败
        () => commit(tpes.CHECKOUT_FAILURE,saveCardItems)    
)
}
}
  • 组件中使用mapActions,组件方法与actions方法进行映射
import {mapActions} from 'vuex'
export default {
    methods: {
       ...mapActions(['increment','incrementBy']),
        ...mapActions({
        add: 'increment'
        })
    }
}
  • actions会返回异步函数Promise
actions: {
    actionsA({commit}) {
        return new Promise((resolve,reject) => {
            setTimeout(() => {
            commit('someMutation')
            resolve()
            },1000)
        })
    }
     actionB ({ dispatch, commit }) {
        return dispatch('actionA').then(() => {
          commit('someOtherMutation')
        })
      }
}

store.dispatch('actionA').then(() => {
  // ...
})


  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // wait for `actionA` to finish
    commit('gotOtherData', await getOtherData())
  }

modules

  • 每一个模块都有独立的state、mutations、actions
  • 每个模块都有本地的state接收参数
const miduleA = {}
const muduleB = {}
const store = createStore({
    modules: {
    a: moduleA,
    b: moduleB
}
})
store.state.a
store.state.b
  • 在actions中本地context.state,根state:context.rootState,({ state, commit, rootState })
  • 在getters中,root state (state, getters, rootState)
  • 模块的命名空间, namespaced: true,getters、actions将会接收本地化的getters、dispatch、commit
  • { root: true }作为dispatch和commit的第三个参数.
  • 注册全局actions
{
  actions: {
    someOtherAction ({dispatch}) {
      dispatch('someAction')
    }
  },
  modules: {
    foo: {
      namespaced: true,

      actions: {
        someAction: {
          root: true,
          handler (namespacedContext, payload) { ... } // -> 'someAction'
        }
      }
    }
  }
}
computed: {
  ...mapState({
    a: state => state.some.nested.module.a,
    b: state => state.some.nested.module.b
  }),
  ...mapGetters([
    'some/nested/module/someGetter', // -> this['some/nested/module/someGetter']
    'some/nested/module/someOtherGetter', // -> this['some/nested/module/someOtherGetter']
  ])
},
methods: {
  ...mapActions([
    'some/nested/module/foo', // -> this['some/nested/module/foo']()
    'some/nested/module/bar' // -> this['some/nested/module/bar']()
  ])
}
// 简化
{
  actions: {
    someOtherAction ({dispatch}) {
      dispatch('someAction')
    }
  },
  modules: {
    foo: {
      namespaced: true,

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

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

export default {
  computed: {
    // look up in `some/nested/module`
    ...mapState({
      a: state => state.a,
      b: state => state.b
    })
  },
  methods: {
    // look up in `some/nested/module`
    ...mapActions([
      'foo',
      'bar'
    ])
  }
}
// get namespace value via plugin option
// and returns Vuex plugin function
export function createPlugin (options = {}) {
  return function (store) {
    // add namespace to plugin module's types
    const namespace = options.namespace || ''
    store.dispatch(namespace + 'pluginAction')
  }
}
  • 动态注册模块
import { createStore } from 'vuex'

const store = createStore({ /* options */ })

// register a module `myModule`
store.registerModule('myModule', {
  // ...
})

// register a nested module `nested/myModule`
store.registerModule(['nested', 'myModule'], {
  // ...
})
// 移除模块
store.unregisterModule(moduleName)
// 检测是否有该模块
store.hasModule(moduleName)
//actions, mutations and getters都会加入到store中,但是state没有
store.registerModule('a', module, { preserveState: true })
  • state会造成state污染,所以采用data的形式,
state: () => ({
    foo:'bar'
})

深层次

应用结构

├── index.html
├── main.js
├── api
│ └── ... # abstractions for making API requests
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # where we assemble modules and export the store
├── actions.js # root actions
├── mutations.js # root mutations
└── modules
├── cart.js # cart module
└── products.js # products module

Composition API

import { computed } from 'vue'
import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()

    return {
      // access a state in computed function
      count: computed(() => store.state.count),

      // access a getter in computed function
      double: computed(() => store.getters.double)
        
    // access a mutation
      increment: () => store.commit('increment'),
    
       // access an action
       asyncIncrement: () => store.dispatch('asyncIncrement')

    }
  }
}

Plugins

const myPlugin = (store) => {
  // called when the store is initialized
  store.subscribe((mutation, state) => {
    // called after every mutation.
    // The mutation comes in the format of `{ type, payload }`.
  })
}
const store = createStore({
  // ...
  plugins: [myPlugin]
})
  • 使用mutations、actions
export default function createWebSocketPlugin (socket) {
  return (store) => {
    socket.on('data', data => {
      store.commit('receiveData', data)
    })
    store.subscribe(mutation => {
      if (mutation.type === 'UPDATE_DATA') {
        socket.emit('update', mutation.payload)
      }
    })
  }
}
const plugin = createWebSocketPlugin(socket)

const store = createStore({
  state,
  mutations,
  plugins: [plugin]
})
  • 快照
const myPluginWithSnapshot = (store) => {
  let prevState = _.cloneDeep(store.state)
  store.subscribe((mutation, state) => {
    let nextState = _.cloneDeep(state)

    // compare `prevState` and `nextState`...

    // save state for next mutation
    prevState = nextState
  })
}
  • 快照只能在开发环境中使用
const store = createStore({
  // ...
  plugins: process.env.NODE_ENV !== 'production'
    ? [myPluginWithSnapshot]
    : []
})
  • logger插件,createVuexLogger全局方法
import { createLogger } from 'vuex'

const store = createStore({
  plugins: [createLogger()]
})
  • 严格模式
const store = createStore({
  // ...
  strict: true
})
const store = createStore({
  // ...
  strict: process.env.NODE_ENV !== 'production'
})

表单处理

  • 第一种方式
<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)
    }
  }
}

动态加载和热重新加载所有模块

// store.js
import Vue from 'vue'
import Vuex from 'vuex'

// Load all modules.
function loadModules() {
  const context = require.context("./modules", false, /([a-z_]+)\.js$/i)

  const modules = context
    .keys()
    .map((key) => ({ key, name: key.match(/([a-z_]+)\.js$/i)[1] }))
    .reduce(
      (modules, { key, name }) => ({
        ...modules,
        [name]: context(key).default
      }),
      {}
    )

  return { context, modules }
}

const { context, modules } = loadModules()

Vue.use(Vuex)

const store = new Vuex.Store({
  modules
})

if (module.hot) {
  // Hot reload whenever any module changes.
  module.hot.accept(context.id, () => {
    const { modules } = loadModules()

    store.hotUpdate({
      modules
    })
  })
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM