692 vuex:store,Vue devtool,单一状态树,组件获取状态,mapState,getters,mapGetters,mutation及常量,mapMutations,actions,mapActions,module、局部状态、命名空间、修改或派发根组件、createNamespacedHelpers

什么是状态管理


复杂的状态管理


Vuex的状态管理


Vuex的状态管理


Vuex的安装


创建Store


组件中使用store


Vue devtool


手动安装devtool


单一状态树


组件获取状态


在setup中使用mapState


getters的基本使用


getters第二个参数


getters的返回函数


mapGetters的辅助函数


Mutation基本使用


Mutation携带数据


Mutation常量类型


mapMutations辅助函数


mutation重要原则


actions的基本使用


actions的分发操作


actions的辅助函数


actions的异步操作


module的基本使用


module的局部状态


module的命名空间


module修改或派发根组件


module的辅助函数


module的辅助函数


对useState和useGetters修改


目录结构


main.js

import { createApp } from 'vue'
import App from './App_nexttick.vue'
import store from './store'

createApp(App).use(store).mount('#app')

App.vue

<template>
  <home />
  <h2>App: {{ $store.state.counter }}</h2>
  <button @click="increment">+1</button>
  <button @click="decrement">-1</button>
</template>

<script>
  import Home from './pages/Home.vue'

  export default {
    name: 'App',
    components: {
      Home,
    },
    methods: {
      increment() {
        this.$store.commit('increment')
      },
      decrement() {
        this.$store.commit('decrement')
      },
    },
  }
</script>

<style>
  #app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
  }
</style>

hooks/index.js

import { useGetters } from './useGetters'
import { useState } from './useState'

export { useGetters, useState }

hooks/useMapper.js

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

export function useMapper(mapper, mapFn) {
  // 拿到store独享
  const store = useStore()

  // 获取到对应的对象的functions: {name: function, age: function}
  const storeStateFns = mapFn(mapper)

  // 对数据进行转换
  const storeState = {}
  Object.keys(storeStateFns).forEach(fnKey => {
    const fn = storeStateFns[fnKey].bind({ $store: store })
    storeState[fnKey] = computed(fn)
  })

  return storeState
}

hooks/useState copy.js

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

export function useState(mapper) {
  // 拿到store独享
  const store = useStore()

  // 获取到对应的对象的functions: {name: function, age: function}
  const storeStateFns = mapState(mapper)

  // 对数据进行转换
  const storeState = {}
  Object.keys(storeStateFns).forEach(fnKey => {
    const fn = storeStateFns[fnKey].bind({ $store: store })
    storeState[fnKey] = computed(fn)
  })

  return storeState
}

hooks/useState.js

import { mapState, createNamespacedHelpers } from 'vuex'
import { useMapper } from './useMapper'

export function useState(moduleName, mapper) {
  let mapperFn = mapState
  if (typeof moduleName === 'string' && moduleName.length > 0) {
    mapperFn = createNamespacedHelpers(moduleName).mapState
  } else {
    mapper = moduleName
  }

  return useMapper(mapper, mapperFn)
}

hooks/useState copy.js

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

export function useState(mapper) {
  // 拿到store独享
  const store = useStore()

  // 获取到对应的对象的functions: {name: function, age: function}
  const storeStateFns = mapState(mapper)

  // 对数据进行转换
  const storeState = {}
  Object.keys(storeStateFns).forEach(fnKey => {
    const fn = storeStateFns[fnKey].bind({ $store: store })
    storeState[fnKey] = computed(fn)
  })

  return storeState
}

hooks/useState.js

import { mapState, createNamespacedHelpers } from 'vuex'
import { useMapper } from './useMapper'

export function useState(moduleName, mapper) {
  let mapperFn = mapState
  if (typeof moduleName === 'string' && moduleName.length > 0) {
    mapperFn = createNamespacedHelpers(moduleName).mapState
  } else {
    mapper = moduleName
  }

  return useMapper(mapper, mapperFn)
}

store-root/index.js

import { createStore } from 'vuex'
import axios from 'axios'
import { INCREMENT_N } from './mutation-types'

const store = createStore({
  state() {
    return {
      counter: 100,
      name: 'why',
      age: 18,
      height: 1.88,
      books: [
        { name: '深入Vuejs', price: 200, count: 3 },
        { name: '深入Webpack', price: 240, count: 5 },
        { name: '深入React', price: 130, count: 1 },
        { name: '深入Node', price: 220, count: 2 },
      ],
      discount: 0.6,
      banners: [],
    }
  },
  getters: {
    totalPrice(state, getters) {
      let totalPrice = 0
      for (const book of state.books) {
        totalPrice += book.count * book.price
      }
      return totalPrice * getters.currentDiscount
    },
    currentDiscount(state) {
      return state.discount * 0.9
    },
    totalPriceCountGreaterN(state, getters) {
      return function (n) {
        let totalPrice = 0
        for (const book of state.books) {
          if (book.count > n) {
            totalPrice += book.count * book.price
          }
        }
        return totalPrice * getters.currentDiscount

        /*
        state.books.reduce((prev, book) => {
          if (book.count <= n) {
            return totalPrice
          } else {
            totalPrice = prev + book.price * book.count
            return totalPrice
          }

          // 踩坑:下面这样写,当book.count <= n时,返回的是undefined,相加结果是NaN,结果是NaN就停止计算
          if (book.count > n) {
            totalPrice = prev + book.price * book.count
            console.log('totalPrice--', totalPrice)
            return totalPrice
          }
        }, 0)
        */
      }
    },
    nameInfo(state) {
      return `name: ${state.name}`
    },
    ageInfo(state) {
      return `age: ${state.age}`
    },
    heightInfo(state) {
      return `height: ${state.height}`
    },
  },
  mutations: {
    increment(state) {
      state.counter++
    },
    decrement(state) {
      state.counter--
    },
    // {n: 10, name: "why", age: 18} -> payload
    [INCREMENT_N](state, payload) {
      console.log(payload)
      state.counter += payload.n
    },
    addBannerData(state, payload) {
      state.banners = payload
    },
  },
  actions: {
    // 放函数
    // 1.参数问题
    incrementAction(context, payload) {
      console.log(payload)
      setTimeout(() => {
        context.commit('increment')
      }, 1000)
    },
    // 2.context的其他属性
    decrementAction({ commit, dispatch, state, rootState, getters, rootGetters }) {
      commit('decrement')
    },
    getHomeMultidata(context) {
      return new Promise((resolve, reject) => {
        axios
          .get('http://123.207.32.32:8000/home/multidata')
          .then(res => {
            context.commit('addBannerData', res.data.data.banner.list)
            resolve({ name: 'hahaha', age: 18 })
          })
          .catch(err => {
            reject(err)
          })
      })
    },
  },
})

export default store

mutation-types.js

export const INCREMENT_N = "increment_n"

store/index.js

import { createStore } from 'vuex'
// **注意: 命名、导出都是homeModule、userModule这种风格,但是导入的时候,要去掉后面的Module
import home from './modules/home'
import user from './modules/user'

const store = createStore({
  state() {
    return {
      rootCounter: 0,
    }
  },
  mutations: {
    increment(state) {
      state.rootCounter++
    },
  },
  modules: {
    home,
    user,
  },
})

export default store

modules/home.js

const homeModule = {
  namespaced: true, // 【module的命名空间。】
  state() {
    return {
      homeCounter: 100,
    }
  },
  getters: {
    // 【有4个参数。】
    doubleHomeCounter(state, getters, rootState, rootGetters) {
      return state.homeCounter * 2
    },
    otherGetter(state) {
      return 100
    },
  },
  mutations: {
    increment(state) {
      state.homeCounter++
    },
  },
  actions: {
    incrementAction({
      commit,
      dispatch,
      state,
      rootState,
      getters,
      rootGetters,
    }) {
      commit('increment')
      // 【module修改或派发根组件】
      commit('increment', null, { root: true }) // 对根store的提交

      // dispatch
      // dispatch("incrementAction", null, {root: true})
    },
  },
}

export default homeModule

user.js

const userModule = {
  namespaced: true,
  state() {
    return {
      userCounter: 10,
    }
  },
  getters: {},
  mutations: {},
  actions: {},
}

export default userModule

01_mapState_compunted.vue

<template>
  <div>
    <h2>Home:{{ $store.state.counter }}</h2>
    <h2>Home:{{ sCounter }}</h2>
    <h2>Home:{{ sName }}</h2>
    <!-- <h2>Home:{{ age }}</h2>
    <h2>Home:{{ height }}</h2> -->
  </div>
</template>

<script>
  import { mapState } from 'vuex'

  export default {
    computed: {
      fullName() {
        return 'Kobe Bryant'
      },
      // 其他的计算属性, 从state获取
      // ...mapState(["counter", "name", "age", "height"])
      ...mapState({
        sCounter: state => state.counter,
        sName: state => state.name,
      }),
    },
  }
</script>

<style scoped></style>

02_mapState_setup.vue

<template>
  <div>
    <h2>Home:{{ $store.state.counter }}</h2>
    <hr />
    <h2>{{ sCounter }}</h2>
    <h2>{{ counter }}</h2>
    <h2>{{ name }}</h2>
    <h2>{{ age }}</h2>
    <h2>{{ height }}</h2>
    <hr />
  </div>
</template>

<script>
  import { computed } from 'vue'
  import { mapState, useStore } from 'vuex'

  export default {
    computed: {
      fullName: function () {
        return '1fdasfdasfad'
      },
      ...mapState(['name', 'age']),
    },

    setup() {
      const store = useStore()
      const sCounter = computed(() => store.state.counter)
      // const sName = computed(() => store.state.name)
      // const sAge = computed(() => store.state.age)

      // {name: function, age: function, height: function}
      const storeStateFns = mapState(['counter', 'name', 'age', 'height'])

      // {name: ref, age: ref, height: ref}
      const storeState = {}
      Object.keys(storeStateFns).forEach(fnKey => {
        const fn = storeStateFns[fnKey].bind({ $store: store })
        storeState[fnKey] = computed(fn)
      })

      return {
        sCounter,
        ...storeState,
      }
    },
  }
</script>

<style scoped></style>

03_useState封装后使用.vue

<template>
  <div>
    <h2>Home:{{ $store.state.counter }}</h2>
    <hr />
    <h2>{{ counter }}</h2>
    <h2>{{ name }}</h2>
    <h2>{{ age }}</h2>
    <h2>{{ height }}</h2>
    <h2>{{ sCounter }}</h2>
    <h2>{{ sName }}</h2>
    <hr />
  </div>
</template>

<script>
  import { useState } from '../hooks/useState'

  export default {
    setup() {
      const storeState = useState(['counter', 'name', 'age', 'height'])
      const storeState2 = useState({
        sCounter: state => state.counter,
        sName: state => state.name,
      })

      return {
        ...storeState,
        ...storeState2,
      }
    },
  }
</script>

<style scoped></style>

04_mapGetters_computed.vue

<template>
  <div>
    <h2>总价值: {{ $store.getters.totalPrice }}</h2>
    <h2>总价值: {{ $store.getters.totalPriceCountGreaterN(1) }}</h2>
    <hr />
    <h2>{{ sNameInfo }}</h2>
    <h2>{{ sAgeInfo }}</h2>
    <!-- <h2>{{ ageInfo }}</h2>
    <h2>{{ heightInfo }}</h2> -->
    <hr />
  </div>
</template>

<script>
  import { mapGetters } from 'vuex'

  export default {
    computed: {
      ...mapGetters(['nameInfo', 'ageInfo', 'heightInfo']),
      ...mapGetters({
        sNameInfo: 'nameInfo',
        sAgeInfo: 'ageInfo',
      }),
    },
    setup() {},
  }
</script>

05_useGetters封装后使用.vue

<template>
  <div>
    <h2>总价值: {{ $store.getters.totalPrice }}</h2>
    <h2>总价值: {{ $store.getters.totalPriceCountGreaterN(1) }}</h2>
    <hr />
    <h2>{{ nameInfo }}</h2>
    <h2>{{ ageInfo }}</h2>
    <h2>{{ heightInfo }}</h2>
    <hr />
  </div>
</template>

<script>
  import { useGetters } from '../hooks/useGetters'

  export default {
    computed: {},
    setup() {
      const storeGetters = useGetters(['nameInfo', 'ageInfo', 'heightInfo'])

      return {
        ...storeGetters,
      }
    },
  }
</script>

06_mutation的细节补充.vue

<template>
  <div>
    <h2>当前计数: {{ $store.state.counter }}</h2>
    <hr />
    <button @click="$store.commit('increment')">+1</button>
    <button @click="$store.commit('decrement')">-1</button>
    <button @click="addTen">+10</button>
    <hr />
  </div>
</template>

<script>
  import { INCREMENT_N } from '../store/mutation-types'

  export default {
    methods: {
      addTen() {
        // this.$store.commit('incrementN', 10)
        // this.$store.commit('incrementN', {n: 10, name: "why", age: 18})
        // 另外一种提交风格
        this.$store.commit({
          type: INCREMENT_N,
          n: 10,
          name: 'why',
          age: 18,
        })
      },
    },
  }
</script>

07_mutations的辅助函数.vue

<template>
  <div>
    <h2>当前计数: {{ $store.state.counter }}</h2>
    <hr />
    <button @click="increment">+1</button>
    <button @click="add">+1</button>
    <button @click="decrement">-1</button>
    <button @click="increment_n({ n: 10 })">+10</button>
    <!-- 加的 -->
    <button @click="addN">Home addN +n</button>
    <button @click="addOne">Home addOne +1</button>
    <hr />
  </div>
</template>

<script>
  import { mapMutations, mapState } from 'vuex'

  import { INCREMENT_N } from '../store/mutation-types'

  export default {
    methods: {
      ...mapMutations(['increment', 'decrement', INCREMENT_N]),
      ...mapMutations({
        add: 'increment',
      }),
      // 下面的代码是加的
      addN() {
        this.increament_n({ num: 30 }) // 加上this啊
        // this[INCREAMENT_N]({num: 30}) // 这样写也可以
      },
      addOne() {
        // 【mapMutations就是把方法映射到当前组件中,所以可以通过this访问方法。】
        this.increament()
      },
    },
    setup() {
      const storeMutations = mapMutations(['increment', 'decrement', INCREMENT_N])

      return {
        ...storeMutations,
      }
    },
  }
</script>

<style scoped></style>


08_actions的使用和细节补充.vue

<template>
  <div>
    <h2>当前计数: {{ $store.state.counter }}</h2>
    <hr />
    <button @click="increment">+1</button>
    <button @click="decrement">-1</button>
    <hr />
  </div>
</template>

<script>
  import axios from 'axios'

  export default {
    methods: {
      increment() {
        this.$store.dispatch('incrementAction', { count: 100 })
      },
      decrement() {
        // 3.派发风格(对象类型)
        this.$store.dispatch({
          type: 'decrementAction',
        })
      },
    },
    mounted() {
      this.$store.dispatch('getHomeMultidata')
    },
    setup() {},
  }
</script>

<style scoped></style>


09_actions的辅助函数.vue

<template>
  <div>
    <h2>当前计数: {{ $store.state.counter }}</h2>
    <hr />
    <button @click="incrementAction">+1</button>
    <button @click="decrementAction">-1</button>
    <button @click="add">+1</button>
    <button @click="sub">-1</button>
    <hr />
  </div>
</template>

<script>
  import { mapActions } from 'vuex'

  export default {
    methods: {
      // ...mapActions(["incrementAction", "decrementAction"]),
      // ...mapActions({
      //   add: "incrementAction",
      //   sub: "decrementAction"
      // })
    },
    setup() {
      const actions = mapActions(['incrementAction', 'decrementAction'])
      const actions2 = mapActions({
        add: 'incrementAction',
        sub: 'decrementAction',
      })

      return {
        ...actions,
        ...actions2,
      }
    },
  }
</script>

10_actions的返回Promise.vue

<template>
  <div>
    <h2>当前计数: {{ $store.state.counter }}</h2>
    <hr />
    <button @click="incrementAction">+1</button>
    <button @click="decrementAction">-1</button>
    <button @click="add">+1</button>
    <button @click="sub">-1</button>
    <hr />
  </div>
</template>

<script>
  import { onMounted } from 'vue'
  import { useStore } from 'vuex'

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

      onMounted(() => {
        const promise = store.dispatch('getHomeMultidata')
        promise.then(res => console.log(res)).catch(err => console.log(err))
      })
    },
  }
</script>

11_module的基本使用.vue

<template>
  <div>
    <h2>{{ $store.state.rootCounter }}</h2>
    <h2>{{ $store.state.home.homeCounter }}</h2>
    <h2>{{ $store.state.user.userCounter }}</h2>
  </div>
</template>

<script>
  export default {
    setup() {},
  }
</script>

12_module的命名空间.vue

<template>
  <div>
    <h2>root: {{ $store.state.rootCounter }}</h2>
    <h2>home: {{ $store.state.home.homeCounter }}</h2>
    <h2>user: {{ $store.state.user.userCounter }}</h2>

    <hr />
    <!-- 【store.getters[]括号中是字符串,字符串包括 模块名/getters名。而store.state后面直接跟模块名,store.state.login.userMenus。】 -->
    <h2>{{ $store.getters['home/doubleHomeCounter'] }}</h2>

    <button @click="homeIncrement">home+1</button>
    <button @click="homeIncrementAction">home+1</button>
  </div>
</template>

<script>
  export default {
    methods: {
      homeIncrement() {
        this.$store.commit('home/increment')
      },
      homeIncrementAction() {
        this.$store.dispatch('home/incrementAction')
      },
    },
  }
</script>

posted on 2021-07-07 13:30  冲啊!  阅读(284)  评论(0编辑  收藏  举报

导航