当前位置: 首页 > news >正文

Vue学习笔记集--Vuex

Vuex

Vuex 是 Vue.js 的官方状态管理库,用于集中管理组件间共享的状态(数据)。

它通过单一数据源(store)实现数据的响应式管理和可预测的状态变更。


核心概念

概念作用特点
State存储应用的状态数据(类似组件的 data唯一数据源,响应式
Getters从 state 派生的计算属性(类似组件的 computed缓存结果,避免重复计算
Mutations唯一修改 state 的方法(同步操作)通过 commit 触发
Actions处理异步操作或复杂逻辑,提交 mutation 间接修改 state通过 dispatch 触发
Modules将 store 拆分为多个模块,便于管理大型应用的状态支持嵌套和命名空间(namespaced)

基本使用

安装与配置
npm install vuex@next  # Vue 3 使用 vuex@4
npm install vuex@3     # Vue 2 使用 vuex@3
创建 Store
// store/index.js
import { createStore } from 'vuex';

const store = createStore({
  state: {
    count: 0,
    user: { name: 'Alice' }
  },
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  mutations: {
    increment(state) {
      state.count++;
    },
    setUser(state, payload) {
      state.user = payload;
    }
  },
  actions: {
    async fetchUser({ commit }, userId) {
      const user = await api.getUser(userId);
      commit('setUser', user);
    }
  },
  modules: {
    // 模块化示例见下文
  }
});

export default store;
挂载到 Vue 实例
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';

const app = createApp(App);
app.use(store); // 注入全局 $store
app.mount('#app');

组件中使用 Vuex

State

存储数据

<template>
  <div>{{ $store.state.count }}</div>
  <div>{{ userName }}</div>
</template>

<script setup>
import { computed } from 'vue';
import { useStore } from 'vuex';

const store = useStore();
const userName = computed(() => store.state.user.name);
</script>

Vuex 的 state 是 Vuex 存储数据的地方,它提供了一种集中式的存储机制,让 Vue 组件能够方便地访问和共享状态。以下是 Vuex 的 state 的使用方法:

定义 state

在 Vuex store 中定义 state,state 是一个对象,用于存储应用的状态数据。

const store = new Vuex.Store({
  state: {
    count: 0,
    todos: [
      { id: 1, text: 'Learn JavaScript', done: false },
      { id: 2, text: 'Learn Vue', done: false },
      { id: 3, text: 'Build a Vue App', done: false }
    ]
  }
})
在组件中访问 state

可以通过 this.$store.state 或者 mapState 辅助函数在组件中访问 state 中的数据。

直接访问
export default {
  computed: {
    count() {
      return this.$store.state.count;
    },
    todos() {
      return this.$store.state.todos;
    }
  }
}
使用 mapState 辅助函数
import { mapState } from 'vuex';

export default {
  computed: {
    ...mapState([
      'count',
      'todos'
    ])
  }
}
修改 state

Vuex 的 state 是响应式的,但只能通过提交 mutation 来修改 state,直接修改 state 不会触发视图更新。

// 提交 mutation
this.$store.commit('increment');

// 或者在组件中使用 methods
methods: {
  increment() {
    this.$store.commit('increment');
  }
}

对应的 mutation 定义如下:

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  }
})
使用模块化 Vuex

在大型应用中,可以将 Vuex store 拆分成多个模块,每个模块有自己的 state、mutations、actions 等。

const moduleA = {
  namespaced: true,
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  }
}

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

在组件中访问模块的 state:

computed: {
  count() {
    return this.$store.state.a.count;
  }
}

或者使用 mapState 辅助函数:

import { mapState } from 'vuex';

export default {
  computed: {
    ...mapState('a', [
      'count'
    ])
  }
}
动态注册模块

可以在应用运行时动态注册模块,方便在需要时添加新的功能。

// 动态注册模块
store.registerModule('b', {
  state: {
    name: 'Module B'
  }
})

// 在组件中访问
computed: {
  name() {
    return this.$store.state.b.name;
  }
}

通过以上方法,可以在 Vue 组件中方便地使用 Vuex 的 state,实现数据的集中管理和共享。

Getters

Vuex 中的 Getters 是用于从 Store 的 state 中派生出状态的计算属性,类似于组件内的 computed 属性。

基本用法
  • 定义 Getter:在 Store 的 getters 对象中定义函数,接收 state 作为第一个参数。

    const store = new Vuex.Store({
      state: {
        todos: [
          { id: 1, done: true },
          { id: 2, done: false }
        ]
      },
      getters: {
        doneTodos: state => state.todos.filter(todo => todo.done)
      }
    });
    
  • 访问 Getter:通过 this.$store.getters.doneTodosmapGetters 辅助函数映射到组件计算属性。

    // 组件中
    computed: {
      ...mapGetters(['doneTodos'])
    }
    
参数与依赖
  • 访问其他 Getter:通过第二个参数 getters 获取其他 Getter。

    getters: {
      doneCount: (state, getters) => getters.doneTodos.length
    }
    
  • 模块中的 Getter:在模块内,可访问模块的 state、根节点的 rootStaterootGetters

    getters: {
      combinedData(state, getters, rootState, rootGetters) {
        // 访问模块和根状态
      }
    }
    
动态参数
  • 返回函数:通过返回函数实现传参,例如根据 ID 查找特定项。

    getters: {
      getTodoById: state => id => state.todos.find(todo => todo.id === id)
    }
    // 使用:store.getters.getTodoById(2)
    
响应式与缓存
  • 响应式更新:当依赖的 state 变化时,Getter 自动重新计算。
  • 缓存机制:结果会被缓存,除非依赖的 state 发生变化,避免重复计算。

Mutation

在 Vuex 中,Mutations 是更改 store 中状态的唯一方式。它们是同步的事务,用于修改 state。以下是如何定义和使用 Mutations 的详细步骤:

定义和使用 Mutations
1. 定义 Mutations

在 Vuex store 中定义 Mutations。Mutations 是一个对象,其中的每个属性是一个函数,这些函数接收 state 作为第一个参数,或者通过参数解构来获取 state 和其他上下文信息。

const store = new Vuex.Store({
  state: {
    count: 0,
    todos: []
  },
  mutations: {
    // 简单的 mutation
    increment(state) {
      state.count++;
    },

    // 带参数的 mutation
    incrementBy(state, amount) {
      state.count += amount;
    },

    // 修改 todos
    setTodos(state, todos) {
      state.todos = todos;
    }
  }
});
2. 在组件中提交 Mutations

可以在组件中通过 this.$store.commit 提交 Mutations。

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
    <button @click="incrementBy">Increment By 5</button>
    <ul>
      <li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  computed: {
    count() {
      return this.$store.state.count;
    },
    todos() {
      return this.$store.state.todos;
    }
  },
  methods: {
    increment() {
      this.$store.commit('increment');
    },
    incrementBy() {
      this.$store.commit('incrementBy', 5);
    },
    fetchTodos() {
      // 模拟异步操作
      setTimeout(() => {
        this.$store.commit('setTodos', [
          { id: 1, text: 'Learn JavaScript' },
          { id: 2, text: 'Learn Vue' }
        ]);
      }, 1000);
    }
  },
  created() {
    this.fetchTodos();
  }
};
</script>
使用 mapMutations 辅助函数

为了简化代码,Vuex 提供了 mapMutations 辅助函数,可以将 store 中的 Mutations 映射到组件的方法中。

import { mapMutations } from 'vuex';

export default {
  methods: {
    ...mapMutations([
      'increment',
      'incrementBy',
      'setTodos'
    ])
  }
};

这样,你就可以直接在组件中使用 incrementincrementBysetTodos 方法,而不需要显式地写 this.$store.commit

Mutations 的参数传递

如果需要向 Mutation 传递参数,可以在 commit 中作为第二个参数传入。

// 在组件中
this.$store.commit('incrementBy', 5);

// 在 store 的 Mutations 中
incrementBy(state, amount) {
  state.count += amount;
}
Mutations 的返回值

Mutations 本身没有返回值,但你可以在提交 Mutation 后执行其他操作。

在 Mutations 中访问 state 和 getters

在 Mutations 中,可以通过参数解构来访问 state 和 getters。

mutations: {
  someMutation({ state, getters }) {
    console.log(state.count);
    console.log(getters.doubleCount);
  }
}
模块化 Vuex 中的 Mutations

在模块化 Vuex 中,Mutations 可以定义在模块内部。

const moduleA = {
  namespaced: true,
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  }
};

const store = new Vuex.Store({
  modules: {
    a: moduleA
  }
});

在组件中提交模块的 Mutation:

this.$store.commit('a/increment');

或者使用 mapMutations

import { mapMutations } from 'vuex';

export default {
  methods: {
    ...mapMutations('a', [
      'increment'
    ])
  }
};
总结
  • Mutations 是更改 Vuex store 中状态的唯一方式。
  • 在组件中通过 this.$store.commit 提交 Mutations。
  • 可以使用 mapMutations 辅助函数简化代码。
  • Mutations 可以接收参数,并在模块化 Vuex 中定义在模块内部。

Action

在 Vuex 中,actions 用于处理异步操作,并可以包含逻辑来提交 mutations,从而更新 state。actions 是 Vuex 中处理业务逻辑的主要场所。

定义和使用 actions
1. 定义 actions

在 Vuex store 中定义 actions。actions 是一个对象,其中的每个属性是一个函数,这些函数接收一个上下文对象作为参数,或者通过参数解构来获取 commitgetters 等。

const store = new Vuex.Store({
  state: {
    count: 0,
    todos: []
  },
  mutations: {
    increment(state) {
      state.count++;
    },
    setTodos(state, todos) {
      state.todos = todos;
    }
  },
  actions: {
    // 简单的 action
    increment({ commit }) {
      commit('increment');
    },

    // 带参数的 action
    incrementBy({ commit }, amount) {
      commit('incrementBy', amount);
    },

    // 异步 action
    fetchTodos({ commit }) {
      // 模拟异步操作
      return new Promise((resolve) => {
        setTimeout(() => {
          commit('setTodos', [
            { id: 1, text: 'Learn JavaScript' },
            { id: 2, text: 'Learn Vue' }
          ]);
          resolve();
        }, 1000);
      });
    }
  }
});
2. 在组件中使用 actions

可以在组件中通过 this.$store.dispatch 触发 actions。

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
    <button @click="fetchTodos">Fetch Todos</button>
    <ul>
      <li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  computed: {
    count() {
      return this.$store.state.count;
    },
    todos() {
      return this.$store.state.todos;
    }
  },
  methods: {
    increment() {
      this.$store.dispatch('increment');
    },
    fetchTodos() {
      this.$store.dispatch('fetchTodos').then(() => {
        console.log('Todos fetched!');
      });
    }
  }
};
</script>
使用 mapActions 辅助函数

为了简化代码,Vuex 提供了 mapActions 辅助函数,可以将 store 中的 actions 映射到组件的方法中。

import { mapActions } from 'vuex';

export default {
  methods: {
    ...mapActions([
      'increment',
      'fetchTodos'
    ])
  }
};

这样,你就可以直接在组件中使用 incrementfetchTodos 方法,而不需要显式地写 this.$store.dispatch

actions 的参数传递

如果需要向 action 传递参数,可以在 dispatch 中作为第二个参数传入。

// 在组件中
this.$store.dispatch('incrementBy', 5);

// 在 store 的 actions 中
incrementBy({ commit }, amount) {
  commit('incrementBy', amount);
}
actions 的返回值

dispatch 会返回一个 Promise,因此可以在触发 action 后使用 .then()async/await 来处理异步操作的结果。

this.$store.dispatch('fetchTodos').then(() => {
  console.log('Todos fetched!');
});
在 actions 中访问 state 和 getters

在 actions 中,可以通过上下文对象访问 state 和 getters。

actions: {
  someAction({ state, getters }) {
    console.log(state.count);
    console.log(getters.doubleCount);
  }
}
模块化 Vuex 中的 actions

在模块化 Vuex 中,actions 可以定义在模块内部。

const moduleA = {
  namespaced: true,
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  },
  actions: {
    increment({ commit }) {
      commit('increment');
    }
  }
};

const store = new Vuex.Store({
  modules: {
    a: moduleA
  }
});

在组件中触发模块的 action:

this.$store.dispatch('a/increment');

或者使用 mapActions

import { mapActions } from 'vuex';

export default {
  methods: {
    ...mapActions('a', [
      'increment'
    ])
  }
};
总结
  • actions 用于处理异步操作和业务逻辑。
  • 在组件中通过 this.$store.dispatch 触发 actions。
  • 可以使用 mapActions 辅助函数简化代码。
  • actions 可以接收参数,并返回 Promise。
  • 在模块化 Vuex 中,actions 可以定义在模块内部,并通过命名空间访问。

辅助函数(简化代码)

Vuex 提供 mapState, mapGetters, mapMutations, mapActions 辅助函数。

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

export default {
  computed: {
    ...mapState(['count']),
    ...mapGetters(['doubleCount']),
  },
  methods: {
    ...mapMutations(['increment']),
    ...mapActions(['fetchUser']),
  }
};
</script>

模块化(Modules)

定义模块
// store/modules/user.js
const userModule = {
  namespaced: true, // 启用命名空间
  state: () => ({ name: 'Guest' }),
  mutations: {
    setName(state, name) {
      state.name = name;
    }
  },
  actions: {
    login({ commit }, name) {
      commit('setName', name);
    }
  }
};

export default userModule;
注册模块
// store/index.js
import userModule from './modules/user';

const store = createStore({
  modules: {
    user: userModule
  }
});
访问模块内容
// 组件中使用命名空间访问
store.commit('user/setName', 'Charlie');
store.dispatch('user/login', 'David');

// 辅助函数指定命名空间
...mapMutations('user', ['setName']),
...mapActions('user', ['login']),

核心原则

  1. 单一数据源:所有共享状态集中存储在 state 中。
  2. 状态只读:不允许直接修改 state,必须通过 mutations
  3. 同步修改mutations 必须是同步函数,确保状态变更可追踪。
  4. 异步操作:异步逻辑放在 actions 中,通过提交 mutations 修改状态。

相关文章:

  • Androidstudio实现引导页文字动画
  • 大理石机械构件在设计的时候需要注意些什么?
  • 如何利用<picture>标签实现更灵活的图片展示,应对不同设备和格式需求?
  • 【Scrapy】Scrapy教程8——处理子链接
  • Kafka集成Debezium监听postgresql变更
  • 快速入手-Django项目模版和静态文件(二)
  • 2025年03月10日人慧前端面试(外包滴滴)
  • 随笔(1)
  • 操作系统复习(第五章 输入与输出管理)
  • 重复的子字符串
  • linux常用符号
  • dcat-admin已完成项目部署注意事项
  • 软件工程面试题(三)
  • redis集群的原理是什么?
  • 【C语言】深入理解指针(一):从基础到高级应用
  • 新手村:逻辑回归-理解02:逻辑回归中的伯努利分布
  • 项目生命周期 和 项目管理生命周期的差异
  • 【002安卓开发方案调研】之Kotlin+Jetpack开发方案
  • 动态规划入门详解
  • 知识图谱中NLP新技术
  • 人民日报任仲平:为什么中国意味着确定性、未来性、机遇性
  • 为何不当教练转型高校管理岗?苏炳添曾吐露过真实的想法
  • 天问三号计划2028年前后发射实施,开放20千克质量资源
  • 法治日报:强制统一店铺广告牌匾事件何以频发?
  • 资深翻译家、斯诺研究专家安危逝世,曾为多位外国元首做口译
  • 2025年度“沪惠保”今日开售:保费维持129元/人,进一步扩增国内外特药种类