Vue

Vuex基本使用

2023-08-20  本文已影响0人  h2coder

依赖版本

配置Vuex

创建Vuex实例(store\index.js)

// Vuex相关配置,注意:Vue2的Vuex版本是3版本
import Vue from 'vue';
import Vuex from 'vuex';

// 注册Vuex插件
Vue.use(Vuex);

// 创建仓库,管理数据
const store = new Vuex.Store({
    // 严格模式,不能直接修改state的数据
    // 默认为false,是可以直接修改的,但我们都要遵循单向数据流,不允许组件中直接修改状态,设置为true,如果直接修改数据,就会报错!!
    strict: true,
    // 状态,存放数据
    state: {
    },
    // 同步修改state的函数,要求修改state,必须通过 mutation 函数
    mutations: {
    },
    actions: {
        // 异步修改数据,异步修改数据必须通过调用 mutation 函数,也就是在 mutation 上套了一层action
    },
    getters: {
        // 类似计算属性,通过计算某个state,或处理多个state属性来得到一个结果
    },
    // 模块
    modules: {
    }
});

// 默认导出
export default store

使用Vuex(main.js)

import Vue from 'vue'
import App from './App.vue'

// 导入Vuex的仓库实例
// import store from './store/index.js' // 完整路径写法
// import store from './store/index'// js后缀可以省略
import store from './store' // 如果js文件的名称为index,index 也可以省略

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  // 挂载到 Vue 的实例上,以后就可以通过Vue的实例,通过 $store 获取到仓库的实例
  store
}).$mount('#app')

开始使用

3种获取Vuex实例的方式

const store = new Vuex.Store({
    // 状态,存放数据
    state: {
        uname: '万大爷'
    },
});

在Vue组件模板中

<div>
    {{ $store.state.uname }}
</div>

在Vue组件的js脚本中

export default {
name: 'App',
components: {
    HelloWorld
},
created() {
    console.log(this.$store)
    // 通过Vue实例上$store,适合在Vue组件的环境下使用
    console.log(this.$store.state.uname)
}

在单独的js文件中

// 单独引入store,适合在非Vue组件环境下的时候使用,例如在 xx.js 中
import store from '@/store'

console.log(store.state.uname);

辅助函数

我们在vuex的state、mutations、actions、getters中,配置变量和函数,都在vuex的JS对象里面,想要获取某个变量或函数,需要一层层调用去取,非常麻烦。

所以vuex提供了4个辅助映射函数,将state、getters的状态变量,映射到组件的计算属性中,将mutations、actions的函数映射到组件的函数中,方便我们通过this.变量名this.函数名来调用

核心概念 - state

state,状态,也就是数据,需要多个组件之间共享的数据

简单使用

const store = new Vuex.Store({
    // 状态,存放数据
    state: {
        uname: '万大爷',
        count: 100,
    },
});
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 直接使用store实例,写起来太繁琐 -->
      uname:{{ $store.state.uname }} count:{{ $store.state.count }}
    </div>
  </div>
</template>

优化,使用辅助映射函数

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 通过计算属性,获取状态数据 -->
      uname:{{ uname }} count:{{ count }}
    </div>
  </div>
</template>

<script>
// mapState:映射state的辅助函数,将vuex中state的数据,映射到 computed 计算属性中
import { mapState } from "vuex";

export default {
    computed: {
        ...mapState(["uname", "count"]),
    }
}
</script>

核心概念 - mutations

注意:不能直接修改state中的值,例如$store.state.count++,默认情况下,vuex是允许这样修改数据的,但vuex不推荐这样做,应该遵循单向数据流,数据在vuex中,修改数据应该通过vuex的mutations或actions去修改,而不应该在子组件中直接修改,否则会导致排错困难

如果想vuex阻止在组件中,直接修改state,可以在vuex的Vuex.Store构造函数,传入的配置对象中,配置strict属性,设置为true,就可以在直接修改时,报错

简单使用

const store = new Vuex.Store({
    // 同步修改state的函数,要求修改state,必须通过 mutation 函数
    // 参数一:state状态,就是vuex的state状态对象
    // 参数二:playload载荷,也就是参数,提交 mutation 时,传的参数(只能是1个参数,多个参数时,使用一个对象或数组包裹)
    mutations: {
        // 添加数量
        addCount(state, playload) {
            state.count += playload.num
        },
        // 更新数量,为指定数量
        updateCount(state, count) {
            state.count = count
        }
    },
});
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 违反vuex的单向数据流的原则,不要这样做 -->
      <button @click="$store.state.count++">(错误)直接修改,count数据</button>
      
      <br />
      
      <!-- 修改state中的数据,要通过调用mutations中的函数来实现 -->
      <button @click="fn1">(正确)通过mutations,修改count数据</button>
    </div>
  </div>
</template>

<script>
export default {
  methods: {
    // 触发 mutations 中的函数来修改状态
    fn1() {
      // commit(),提交函数的参数,是 mutations 中要执行的函数名
      this.$store.commit("addCount")
      
      // 传递参数,注意只能传一个参数,多个参数要用对象或数组包裹
      this.$store.commit("addCount", {
        num: 100,
        num2: 200,
      });
    },
  }
}
</script>

优化,使用辅助映射函数

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 违反vuex的单向数据流的原则,不要这样做 -->
      <button @click="$store.state.count++">(错误)直接修改,count数据</button>
      
      <br />
      
      <!-- 修改state中的数据,要通过调用mutations中的函数来实现 -->
      <button @click="fn1">(正确)通过mutations,修改count数据</button>
    </div>
  </div>
</template>

<script>
// mapMutations:映射mutation的辅助函数,映射到 methods 中
import { mapMutations } from "vuex";

export default {
  methods: {
    // 触发 mutations 中的函数来修改状态
    fn1() {
      // commit(),提交函数的参数,是 mutations 中要执行的函数名
      // this.$store.commit("addCount")
      // 传递参数,注意只能传一个参数,多个参数要用对象或数组包裹
      // this.$store.commit("addCount", {
      //   num: 100,
      //   num2: 200,
      // });

      // 调用 mapMutations 映射后的函数
      this.addCount({
        num: 100,
        num2: 200,
      });
    },
    // 映射mutations中的函数,到methods中,然后就可以通过 this.addCount() 来调用 mutations 中的函数
     ...mapMutations(["addCount"]),
   }
}
</script>

核心概念 - actions

简单使用

const store = new Vuex.Store({
    actions: {
        // 异步修改数据,异步修改数据必须通过调用 mutation 函数,也就是在 mutation 上套了一层action
        // 参数一:context上下文,能获取到store身上的哪些属性和方法
        // 参数二,参数,派发 action 时,传的参数,传的参数(只能是1个参数,多个参数时,使用一个对象或数组包裹)
        updateAsyncCount(context, num) {
            setTimeout(() => {
                // 修改数据,提交mutation,同步修改数据
                context.commit("updateCount", num)
                console.log(`异步修改数据成功,新值为${num}`);
            }, 1000);
        }
    },
});
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <button @click="fn2">异步,修改数据</button>
    </div>
  </div>
</template>

<script>
export default {
  methods: {
    // 触发 mutations 中的函数来修改状态
    fn2() {
      // 异步修改数据,触发action函数
      // dispatch(),派发函数的参数,是 actions 中要执行的函数名
      // 传递参数,同样也是智能传递一个参数,多个参数要用对象或数组包裹
      this.$store.dispatch("updateAsyncCount", 888)
    },
  }
}
</script>

优化,使用辅助映射函数

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <button @click="fn2">异步,修改数据</button>
    </div>
  </div>
</template>

<script>
// mapActions:映射action的辅助函数,映射到 methods 中
import { mapActions } from "vuex";

export default {
  methods: {
    fn2() {
      // 调用 mapActions 映射后的函数
      this.updateAsyncCount(888);
    },
    // 映射actions中的函数,到methods中,然后就可以通过this.updateAsyncCount() 来调用 actions 中的函数
     ...mapActions(["updateAsyncCount"]),
   }
}
</script>

核心概念 - getters

基本使用

const store = new Vuex.Store({
    // 状态,存放数据
    state: {
        list: [1, 2, 3, 4, 5, 6]
    },
    getters: {
        // 类似计算属性,通过计算某个state,或处理多个state属性来得到一个结果
        total(state) {
            return state.list.reduce((prev, current) => {
                return prev + current
            }, 0)
        }
    },
});
<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 使用vuex的getters属性 -->
      gettes属性:{{ $store.getters.total }}
    </div>
  </div>
</template>

<script>
    export default {
      name: "App",
      created() {
        // 获取 getters 属性,类似于计算属性
        console.log(this.$store.getters.total);
    }
</script>

优化,使用辅助映射函数

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 使用vuex的getters属性 -->
      gettes属性:{{ total }}
    </div>
  </div>
</template>

<script>
// mapGetters:映射getters的辅助函数,映射到 computed 计算属性中
import { mapGetters } from "vuex";

export default {
  computed: {
    // 映射vuex的getters属性
    ...mapGetters(["total"]),
   }
}
</script>

模块化

创建和配置模块

// 用户模块的store
const state = () => ({
})

const getters = {
}

// 同步操作state数据
const mutations = {
}

// 异步操作state
const actions = {
}

export default {
    // 开启命名空间,这样 mapState、mapMutations、mapActions等辅助函数,才能使用该模块
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}
// Vuex相关配置,注意:Vue2的Vuex版本是3版本
import Vue from 'vue';
import Vuex from 'vuex';

// 引入用户模块的store
import user from '@/store/modules/user'

// 注册Vuex插件
Vue.use(Vuex);

// 创建仓库,管理数据
const store = new Vuex.Store({
    ...省略其他配置
    
    // 模块
    modules: {
      // 模块名:模块对象
      // user: user
      user
    }
});

// 默认导出
export default store

使用方式的变化

准备数据

// 用户模块的store
const state = () => ({
    userInfo: {
        name: 'zs',
        age: 18
    },
    num: 100
})

const getters = {
    // 返回格式化年龄的字符串
    age(state) {
        return state.num + '岁'
    },
}

// 同步操作state数据
const mutations = {
    // 修改 num 数据
    updateNum(state) {
        state.num++
    }
}

// 异步操作state
const actions = {
    updateAsyncNum(context) {
        // 1秒后,提交mutation,更新state
        setTimeout(() => {
            context.commit("updateNum")
        }, 1000);
    }
}

export default {
    // 开启命名空间,这样 mapState、mapMutations、mapActions等辅助函数,才能使用该模块
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}

关于state

使用模块后,之前的使用方式都需要加上模块名

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 模块数据,直接获取,太繁琐 -->
      用户模块-name:{{ $store.state.user.userInfo.name }} 用户模块-age:{{
        $store.state.user.userInfo.age
      }}
      
      <br />

      <!-- 模块数据,使用mapState辅助函数 -->
      用户模块-name:{{ userInfo.name }} 用户模块-age:{{ userInfo.age }}
    </div>
  </div>
</template>

<script>
// mapState:映射state的辅助函数,将vuex中state的数据,映射到 computed 计算属性中
import { mapState } from "vuex";

export default {
  created() {
    console.log(this.$store.state.user);
    console.log(this.$store.state.user.userInfo.name);
    console.log(this.$store.state.user.userInfo.age);
  },
  computed: {
    // 映射vuex的state属性
    ...mapState("user", ["userInfo", "num"]),
   }
}
</script>

关于mutations

使用模块后,之前的使用方式都需要加上模块名

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      user模块的mutation:<button @click="fn3">{{ num }}</button>
    </div>
  </div>
</template>

<script>
// mapMutations:映射mutation的辅助函数,映射到 methods 中
import { mapMutations } from "vuex";

export default {
  methods: {
    fn3() {
      // 调用user模块的mutation函数,格式:模块名/函数名
      this.$store.commit("user/updateNum");
      
      // 使用mapMutations辅助函数,映射后mutation函数
      this.updateNum();
    },
    // 映射user模块的mutation函数
    ...mapMutations("user", ["updateNum"]),
  }
}
</script>

关于actions

使用模块后,之前的使用方式都需要加上模块名

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      user模块的action:<button @click="fn4">{{ num }}</button>
    </div>
  </div>
</template>

<script>
// mapActions:映射action的辅助函数,映射到 methods 中
import { mapActions } from "vuex";

export default {
  methods: {
    fn4() {
      // 调用user模块的action函数,格式:模块名/函数名
      this.$store.dispatch("user/updateAsyncNum")

      // 使用mapActions辅助函数,映射后的action函数
      this.updateAsyncNum();
    },
    // 映射user模块的action模块
    ...mapActions("user", ["updateAsyncNum"]),
  }
}
</script>

关于getters

使用模块后,之前的使用方式都需要加上模块名

注意:getters和state虽然都是类似属性的变量,但是在加入模块后,写法是有区别的,例如

可以看见,getters没有像state那样,在getters下再新建一个模块名的对象,而是在属性名的基础上增加模块和斜杠。那么在JS中,就必须使用中括号来访问了,也就是$store.getters['user/age'],而不能是$store.getters.'user/age',因为这是不合法的

<template>
  <div id="app">
    <h1>根组件</h1>
    <div>
      <!-- 直接使用user模块的getter属性,太繁琐 -->
      user模块的getters:<span>年龄 {{ $store.getters['user/age'] }}</span>
      <br>
      <!-- 使用mapGetters辅助函数,映射的getter属性 -->
      user模块的getters:<span>年龄 {{ age }}</span>
    </div>
  </div>
</template>

<script>
// mapGetters:映射getters的辅助函数,映射到 computed 计算属性中
import { mapGetters } from "vuex";

export default {
  created() {
    // 获取user模块的getter属性
    console.log(this.$store.getters['user/age']);
  },
  computed: {
    // user模块中的getter
    ...mapGetters('user', ['age'])
  }
}
</script>
上一篇 下一篇

猜你喜欢

热点阅读