美文网首页
Vuex的基本使用

Vuex的基本使用

作者: FoxLayla | 来源:发表于2020-03-11 14:16 被阅读0次

    原文:https://laylawang17.github.io/2020/03/11/Vuex%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/

    在我们使用 Vue 搭建的 App 里,当访问数据对象时,一个组件实例只是简单的代理访问。当 App 结构复杂、组件较多时,如果有一处需要被多个实例共享的状态,可以简单的通过维护一份数据来实现共享,这就促成了我们对状态管理机制对需要,比如 Vuex。

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

    原理

    Vuex 是基于 Flux 架构的状态管理库。可以参考 理解 Flux 这篇文章先做一些基础对了解。Vuex 的核心思想就是store 模式,即:将需要共享的状态放在在 store 自身的 action 中管理

    var store = {
      state: {...},
      action: {...}
    };
    

    则组件实例的 state 可以包含共享状态和私有状态两类

    var vm = new Vue({
      data: {
        privateState: {},
        sharedState: {}
      }
    });
    

    store 和组件的关系如下图

    <img src="http://ww1.sinaimg.cn/large/98792392ly1gconn3v15sj20xc0xcjrg.jpg" style="zoom:40%;" />

    对于小型应用来说,我们使用简单的 store 模式就足以让我们的 App 内部变得简单明了,但是对于大型应用借助 Vuex 可能是更好的选择。

    核心概念

    • Store:store 用来管理状态,包括数据和各种方法,由 state、getters、mutations、actions、plugins 组成
    • State:state 中定义了组件所有的状态
    • Getter:getter 可以看作是由 state 派生的“计算属性”
    • Mutations:包含真正实现 state 更新的业务逻辑
    • Action:定义更新 state 的动作,用于知会 mutation 何时处理变更

    在使用 Vuex 的 App 中,当用户与 App 交互时发生的事情包括:

    • 启动 App 时,View 从 store 中获取所需的 state(以及 getters)
    • 用户进行输入、点击等操作时,View 发送(dispatch)相应的 action 给 store,action 中包含了操作类型及数据
    • action 会提交(commit)对应的 mutation
    • mutation 中完成真正的业务逻辑并更新 state
    • View 监听 state 的变化并重新渲染

    基本使用

    Store

    创建 store

    const store = new Vuex.Store({
      state,
      getters,
      mutations,
      actions,
      plugins
    });
    

    以简单的计数 App 为例:

    const store = new Vuex.Store({
      // 状态
      state: {
        count: 0
      },
      // 注册mutation
      mutations: {
        increment(state) {
          state.count++;
        }
      }
    });
    

    从根组件注入 store

    Vue.use(vuex);
    const app = new Vue({
      el: '#app',
      store,
      component: {...},
      template: ...
    });
    

    State

    在子组件中作为一个计算属性获取 state

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

    更简单的方法是使用 Vuex 提供的mapState()方法

    computed: {
      ...mapState(['count'])
    }
    

    computed对象里还可以有组件私有的其他计算属性。

    Getter

    如 Todo List App 可能需要获得状态为 active 的 todo 列表:

    const store = new Vuex.Store({
      state: {
        todos: [...]
      },
      getters: {
        activeTodos: state => state.todos.filter(todo => todo.active),
        // 接收其他getter作为第二个参数
        leftItems: (state, getters) => getters.activeTodos.length,
        // 定义可作为方法调用的带参getter
        getTodoById: state => id => state.todos.find(todo => todo.id === id)
      }
    })
    

    getters 在子组件中可作为计算属性访问

    computed: {
      activeTodos: function() {
        return this.$store.getters.activeTodos;
      }
    }
    

    或者使用mapGetters()方法访问

    computed: {
      ...mapGetters(['activeTodos', 'leftItems'])
    }
    

    Mutation

    在 store 中注册包含载荷的 mutation

    mutations: {
      increment (state, amount) {
        state.count += amount;
      }
    }
    

    注册的 mutation 都必须是同步函数,否则会导致状态的改变不可追踪。

    提交 mutations

    store.commit("increment");
    

    提交带载荷的 mutations

    store.commit("increment", { amount: 2 });
    store.commit({
      type: "increment",
      amount: 2
    });
    

    在组件中提交 mutations

    this.$store.commit("increment");
    

    或者使用mapMutations()方法

    methods: {
      ...mapMutations(['increment'])
    }
    

    Action

    在 store 中注册 action

    action: {
      increment (context) {
        context.commit('increment');
      }
    }
    

    action 函数接收的 context 参数与 store 实例具有相同的方法和 getters,因此可以通过context.statecontext.getters 来获取 state 和 getters,也可以调用 context.commit 提交一个 mutation。

    action 和 mutation 的区别在于:

    • action 需要通过提交 mutation 来实现状态的更新
    • action 中可以包含异步操作,例如
    // 假设 getData() 和 getOtherData() 返回的是 Promise
    
    actions: {
      async actionA ({ commit }) {
        commit('gotData', await getData());
      },
      async actionB ({ dispatch, commit }) {
        await dispatch('actionA'); // 等待 actionA 完成
        commit('gotOtherData', await getOtherData());
      }
    }
    

    分发 action

    store.dispatch("increment", { amount: 2 });
    store.dispatch({
      type: "increment",
      amount: 2
    });
    

    在组件中则需要使用this.$store.dispatch(...)或者mapActions()方法:

    methods: {
      ...mapActions(['increment'])
    }
    

    Plugin

    plugin 中会暴露出每次 mutation 的钩子,用于中 mutation 之后做额外的处理,例如数据持久化等

    const localStoragePlugin = store => {
      // 当 store 初始化后调用
      store.subscribe((mutation, state) => {
        // 每次 mutation 之后调用
        // mutation 的格式为 { type, payload }
        localStorage.setItem("todos", JSON.stringify(state.todos));
      });
    };
    

    参考

    相关文章

      网友评论

          本文标题:Vuex的基本使用

          本文链接:https://www.haomeiwen.com/subject/fuhcjhtx.html