Vuex 四大核心辅助函数详解

2740字

Vuex 四大核心辅助函数详解

Vuex 是 Vue.js 应用程序的状态管理模式和库。当我们的应用逐渐复杂,组件之间共享和传递状态变得困难时,Vuex 提供了一个集中的存储来管理所有组件的状态。为了更方便地在组件中使用 Vuex store 中的状态 (state)、取值器 (getters)、变更 (mutations) 和动作 (actions),Vuex 提供了这些辅助函数。它们的主要目的是简化模板代码,减少冗余。


🗺️ mapState

mapState 辅助函数用于帮助我们方便地在组件的计算属性 (computed) 中映射 store 中的 state。

🧩 不用 mapState

当不使用 mapState 时,我们需要为每一个需要从 store 中读取的状态手动创建一个计算属性。

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Message: {{ message }}</p>
    <p>User: {{ user.firstName }} {{ user.lastName }}</p>
  </div>
</template>

<script>
export default {
  computed: {
    // 手动定义计算属性来获取 store 中的 state
    count() {
      return this.$store.state.count; // 直接访问 $store.state
    },
    message() {
      return this.$store.state.message; // 直接访问 $store.state
    },
    user() {
      return this.$store.state.user; // 直接访问 $store.state
    }
  }
};
</script>

注释说明:

  • computed 对象中,我们为 countmessageuser 分别定义了计算属性。
  • 每个计算属性都返回 this.$store.state 中对应的状态值。

✅ 用了 mapState

使用 mapState 后,代码会变得更加简洁。它可以接收一个数组或一个对象作为参数。

1. 传递字符串数组:

当映射的计算属性的名称与 state 子树的名称相同时。

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Message: {{ message }}</p>
    <p>Local Computed: {{ localComputed }}</p>
  </div>
</template>

<script>
import { mapState } from 'vuex';

export default {
  data() {
    return {
      localData: '这是局部数据'
    };
  },
  computed: {
    // 局部计算属性
    localComputed() {
      return this.localData.toUpperCase();
    },
    // 使用 mapState 辅助函数将 store 中的 state 映射到局部计算属性
    ...mapState([
      'count',   // 映射 this.count  store.state.count
      'message'  // 映射 this.message  store.state.message
    ])
  }
};
</script>

注释说明:

  • 我们从 vuex 导入 mapState 函数。
  • 使用对象展开运算符 (...) 将 mapState 返回的对象混入到 computed 对象中。
  • mapState(['count', 'message']) 会生成 { count() { return this.$store.state.count }, message() { return this.$store.state.message } }

2. 传递对象:

当映射的计算属性的名称与 state 子树的名称不同,或者需要更复杂的取值时。

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <div>
    <p>Current Count: {{ currentCount }}</p>
    <p>App Message: {{ appMessage }}</p>
    <p>Full Name: {{ fullName }}</p>
  </div>
</template>

<script>
import { mapState } from 'vuex';

export default {
  computed: {
    ...mapState({
      currentCount: 'count', //  this.currentCount 映射为 store.state.count
      appMessage: state => state.message, // 可以使用函数进行更灵活的映射
      fullName: state => `${state.user.firstName} ${state.user.lastName}` // 访问深层嵌套的状态
    })
  }
};
</script>

注释说明:

  • currentCount: 'count' 表示将组件内的计算属性 currentCount 映射到 Vuex store 中的 state.count
  • appMessage: state => state.messagefullName: state => ... 展示了如何使用函数来获取 state,这提供了更大的灵活性,例如当 state 的值需要计算或来自嵌套对象时。

📊 mapGetters

mapGetters 辅助函数用于将 store 中的 getters 映射到组件的计算属性 (computed) 中。Getters 可以看作是 store 的计算属性。

🧩 不用 mapGetters

不使用 mapGetters 时,你需要为每个 getter 手动创建计算属性。

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<template>
  <div>
    <p>Doubled Count: {{ doubledCountValue }}</p>
    <p>Welcome: {{ welcomeText }}</p>
  </div>
</template>

<script>
export default {
  computed: {
    // 手动定义计算属性来获取 store 中的 getter
    doubledCountValue() {
      return this.$store.getters.doubledCount; // 通过 $store.getters 访问
    },
    welcomeText() {
      return this.$store.getters.welcomeMessage; // 通过 $store.getters 访问
    }
  }
};
</script>

注释说明:

  • doubledCountValuewelcomeText 计算属性分别从 this.$store.getters 获取对应的 getter 值。

✅ 用了 mapGetters

使用 mapGetters 可以简化这个过程。它也支持数组和对象两种形式。

1. 传递字符串数组:

当映射的计算属性的名称与 getter 的名称相同时。

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<template>
  <div>
    <p>Doubled Count: {{ doubledCount }}</p>
    <p>Welcome: {{ welcomeMessage }}</p>
  </div>
</template>

<script>
import { mapGetters } from 'vuex';

export default {
  computed: {
    // 使用 mapGetters 辅助函数将 store 中的 getters 映射到局部计算属性
    ...mapGetters([
      'doubledCount',   // 映射 this.doubledCount  store.getters.doubledCount
      'welcomeMessage'  // 映射 this.welcomeMessage  store.getters.welcomeMessage
    ])
  }
};
</script>

注释说明:

  • mapGetters(['doubledCount', 'welcomeMessage']) 会生成相应的计算属性,它们的值来源于 Vuex store 中的同名 getters。

2. 传递对象:

当映射的计算属性的名称与 getter 的名称不同时。

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<template>
  <div>
    <p>Calculated Double: {{ calcDouble }}</p>
    <p>Greeting: {{ greeting }}</p>
  </div>
</template>

<script>
import { mapGetters } from 'vuex';

export default {
  computed: {
    ...mapGetters({
      calcDouble: 'doubledCount',   //  this.calcDouble 映射为 store.getters.doubledCount
      greeting: 'welcomeMessage'   //  this.greeting 映射为 store.getters.welcomeMessage
    })
  }
};
</script>

注释说明:

  • calcDouble: 'doubledCount' 将组件的 calcDouble 计算属性映射到 store 的 doubledCount getter。

🧬 mapMutations

mapMutations 辅助函数用于将 store 中的 mutations 映射到组件的 methods 中。这样你就可以在组件方法中直接调用 this.mutationName(payload) 来提交 mutation,而不是使用 this.$store.commit('mutationName', payload)

🧩 不用 mapMutations

不使用 mapMutations 时,你需要为每个 mutation 手动创建方法来调用 this.$store.commit

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <div>
    <p>Count: {{ $store.state.count }}</p>
    <button @click="incrementCountManually">Increment Count Manually</button>
    <button @click="setMessageManually('New Manual Message')">Set Message Manually</button>
  </div>
</template>

<script>
export default {
  methods: {
    // 手动定义方法来提交 mutation
    incrementCountManually() {
      this.$store.commit('INCREMENT_COUNT', 5); // 手动调用 $store.commit
    },
    setMessageManually(newMessage) {
      this.$store.commit('SET_MESSAGE', newMessage); // 手动调用 $store.commit
    }
  }
};
</script>

注释说明:

  • incrementCountManually 方法通过 this.$store.commit('INCREMENT_COUNT', 5) 来提交 INCREMENT_COUNT mutation,并传递 payload 5
  • setMessageManually 方法提交 SET_MESSAGE mutation,并传递新的消息字符串。

✅ 用了 mapMutations

使用 mapMutations 可以将 mutations 映射为组件的 methods。

1. 传递字符串数组:

当映射的方法名与 mutation 名相同时。

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <div>
    <p>Count: {{ $store.state.count }}</p>
    <p>Message: {{ $store.state.message }}</p>
    <button @click="INCREMENT_COUNT(2)">Increment Count</button> <button @click="SET_MESSAGE('Hello from mapMutations!')">Set Message</button> </div>
</template>

<script>
import { mapMutations } from 'vuex';

export default {
  methods: {
    // 使用 mapMutations 辅助函数将 store 中的 mutations 映射到局部方法
    ...mapMutations([
      'INCREMENT_COUNT', // 映射 this.INCREMENT_COUNT()  this.$store.commit('INCREMENT_COUNT')
      'SET_MESSAGE'      // 映射 this.SET_MESSAGE()  this.$store.commit('SET_MESSAGE')
    ])
    // 调用 this.INCREMENT_COUNT(payload) 等同于 this.$store.commit('INCREMENT_COUNT', payload)
  }
};
</script>

注释说明:

  • mapMutations(['INCREMENT_COUNT', 'SET_MESSAGE']) 会将 INCREMENT_COUNTSET_MESSAGE mutations 映射为组件的同名方法。
  • 调用 this.INCREMENT_COUNT(2) 时,2 会作为 payload 传递给 INCREMENT_COUNT mutation。

2. 传递对象:

当映射的方法名与 mutation 名不同时。

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <div>
    <p>Count: {{ $store.state.count }}</p>
    <button @click="addCount(3)">Add to Count</button>
    <button @click="changeMessage('Message updated via alias!')">Change App Message</button>
  </div>
</template>

<script>
import { mapMutations } from 'vuex';

export default {
  methods: {
    ...mapMutations({
      addCount: 'INCREMENT_COUNT', //  this.addCount() 映射为 this.$store.commit('INCREMENT_COUNT')
      changeMessage: 'SET_MESSAGE' //  this.changeMessage() 映射为 this.$store.commit('SET_MESSAGE')
    })
    // 调用 this.addCount(payload) 等同于 this.$store.commit('INCREMENT_COUNT', payload)
  }
};
</script>

注释说明:

  • addCount: 'INCREMENT_COUNT' 将组件的 addCount 方法映射到名为 INCREMENT_COUNT 的 mutation。调用 this.addCount(3) 实际上是执行 this.$store.commit('INCREMENT_COUNT', 3)

🚀 mapActions

mapActions 辅助函数用于将 store 中的 actions 映射到组件的 methods 中。这样你就可以在组件方法中直接调用 this.actionName(payload) 来分发 action,而不是使用 this.$store.dispatch('actionName', payload)

🧩 不用 mapActions

不使用 mapActions 时,你需要为每个 action 手动创建方法来调用 this.$store.dispatch

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
  <div>
    <p>Count: {{ $store.state.count }}</p>
    <p>Message: {{ $store.state.message }}</p>
    <button @click="incrementAsyncManually">Increment Async Manually</button>
    <button @click="updateMsgManually('Async new message')">Update Message Async Manually</button>
  </div>
</template>

<script>
export default {
  methods: {
    // 手动定义方法来分发 action
    incrementAsyncManually() {
      // 手动调用 $store.dispatch,并传递 payload 对象
      this.$store.dispatch('incrementAsync', { amount: 10, delay: 500 });
    },
    updateMsgManually(newMessage) {
      // 手动调用 $store.dispatch
      this.$store.dispatch('updateMessage', newMessage);
    }
  }
};
</script>

注释说明:

  • incrementAsyncManually 方法通过 this.$store.dispatch 分发 incrementAsync action,并传递包含 amountdelay 的 payload 对象。
  • updateMsgManually 方法分发 updateMessage action。

✅ 用了 mapActions

使用 mapActions 可以将 actions 映射为组件的 methods。

1. 传递字符串数组:

当映射的方法名与 action 名相同时。

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
  <div>
    <p>Count: {{ $store.state.count }}</p>
    <p>Message: {{ $store.state.message }}</p>
    <button @click="incrementAsync({ amount: 3, delay: 1500 })">Increment Async</button>
    <button @click="updateMessage('Hello from mapActions!')">Update Message</button>
  </div>
</template>

<script>
import { mapActions } from 'vuex';

export default {
  methods: {
    // 使用 mapActions 辅助函数将 store 中的 actions 映射到局部方法
    ...mapActions([
      'incrementAsync', // 映射 this.incrementAsync()  this.$store.dispatch('incrementAsync')
      'updateMessage'   // 映射 this.updateMessage()  this.$store.dispatch('updateMessage')
    ])
    // 调用 this.incrementAsync(payload) 等同于 this.$store.dispatch('incrementAsync', payload)
  }
};
</script>

注释说明:

  • mapActions(['incrementAsync', 'updateMessage'])incrementAsyncupdateMessage actions 映射为组件的同名方法。
  • 调用 this.incrementAsync({ amount: 3, delay: 1500 }) 时,该对象会作为 payload 传递给 incrementAsync action。

2. 传递对象:

当映射的方法名与 action 名不同时。

代码段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <div>
    <p>Count: {{ $store.state.count }}</p>
    <button @click="addAsync({ amount: 7 })">Add to Count Async</button>
    <button @click="modifyMessage('Asynchronously changed message!')">Modify App Message Async</button>
  </div>
</template>

<script>
import { mapActions } from 'vuex';

export default {
  methods: {
    ...mapActions({
      addAsync: 'incrementAsync', //  this.addAsync() 映射为 this.$store.dispatch('incrementAsync')
      modifyMessage: 'updateMessage' //  this.modifyMessage() 映射为 this.$store.dispatch('updateMessage')
    })
    // 调用 this.addAsync(payload) 等同于 this.$store.dispatch('incrementAsync', payload)
  }
};
</script>

注释说明:

  • addAsync: 'incrementAsync' 将组件的 addAsync 方法映射到名为 incrementAsync 的 action。调用 this.addAsync({ amount: 7 }) 实际上是执行 this.$store.dispatch('incrementAsync', { amount: 7 })

总结一下,Vuex 的辅助函数 (mapState, mapGetters, mapActions, mapMutations) 大大简化了在 Vue 组件中与 store 的交互,使得代码更加简洁、易读和易于维护。它们通过将 store 的属性和方法直接映射到组件的 computedmethods 中,减少了模板和脚本中的冗余代码。

如对内容有异议,请联系关邮箱2285786274@qq.com修改