Vuex 基础用法

2023-05-17 16:25:54 浏览数 (1)

# Hello Vuex

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

  • 安装
代码语言:javascript复制
vue add vuex

# 基础使用

State

  • 将应用全局状态定义在 state
代码语言:javascript复制
// store/index.js
export default new Vuex.Store({
  state: {
    isLogin: false,
  }
});

Mutation

  • 修改 state 只能通过 mutation
代码语言:javascript复制
export default new Vuex.Store({
  // ...
  mutations: {
    login(state) {
      state.isLogin = true;
    },
    logout(state) {
      state.isLogin = false;
    },
  }
});

获取和修改状态

  • 使用 $store.state 获取属性
代码语言:javascript复制
<button @click="login" v-if="!$store.state.isLogin">Login</button>
<button @click="logout" v-else>Logout</button>

  • 修改状态只能通过 store.dispatch(mutation)
代码语言:javascript复制
this.$store.commit('login');
this.$store.commit('logout');

Action

  • Action 类似于 mutation
  • 但是,Action 提交的是 mutation,而不是直接变更状态
  • Action 可以包含任意异步操作
代码语言:javascript复制
// store/index.js
actions: {
  // 参数1 是vuex传递的上下文context
  login({ commit }, username) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (username === 'admin') {
          commit('login');
          resolve();
        } else {
          reject();
        }
      }, 1000);
    });
  },
}

  • 派发动作
代码语言:javascript复制
this.$store.dispatch('login', 'admin').then(() => {
  // 业务逻辑
})

# 模块化

使用 modules 定义多个子模块利于组件复杂状态

代码语言:javascript复制
import user from './user'
export default new Vuex.Store({
  modules: {
    user,
  }
})

在子模块中维护状态

代码语言:javascript复制
export default {
  namespaced: true, // 避免命名冲突
  // 状态及维护逻辑
}

访问方式加上命名空间

代码语言:javascript复制
this.$store.dispatch('user/login', 'admin').then(() => {})

this.$store.commit('user/logout');

// store.state.user.isLogin

# mapState()/mapMutation()/mapAction()

通过这些方法,可以简化访问方式

代码语言:javascript复制
import { mapState } from 'vuex';
export default {
  // 展开后可直接访问 isLogin
  computed: {
    ...mapState('user', ['isLogin']),
  }
}

维护

代码语言:javascript复制
import { mapActions } from 'vuex';
export default {
  methods: {
    login() {
      this.['user/login']('admin').then(() => {})
    },
    ...mapActions(['user/login', 'user/logout']),
  }
}

# Getter

可以用 gettersstorestate 中派生出一些状态,类似于计算属性

代码语言:javascript复制
export default {
  namespaced: true, // 设置独立命名空间,避免命名冲突
  state: {
    isLogin: false,
    username: '',
  },
  getters: {
    welcome: (state) => `${state.username},欢迎回来`,
  },
}

# 严格模式

严格模式下,强制要求状态变更必须由 mutation 维护

代码语言:javascript复制
export default new Vuex.Store({
  strict: true,
})

# 插件

Vuex 的 store 接受 plugins 选项,这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数,它接收 store 作为唯一参数

代码语言:javascript复制
const myPlugin = (store) => {
  // 当 store 初始化后调用
};

插件注册

代码语言:javascript复制
const store = new Vuex.Store({
  // ...
  plugins: [myPlugin],
});

# 简易实现

Vuex 集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化。

# 需求分析

  • 实现一个插件:声明 Store 类,挂载 $store
  • Store 具体实现
    • 创建响应式的 state,保存 mutationsactionsgetters
    • 实现 commit 根据用户传入 type 执行对应 mutation
    • 实现 dispatch 根据用户传入 type 执行对应 action,同时传递上下文
    • 实现 getters,按照 getters 定义对 state 做派生

# 实现

  1. 实现一个插件
代码语言:javascript复制
// cvuex.js
let Vue;
class Store {
  constructor(options) {
    // 响应化处理state
    this.state = new Vue({
      data: options.state,
    })
  }
}
function install(_Vue) {
  Vue = _Vue;
  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store;
      }
    }
  })
}
// cvuex
export default {
  Store,
  install,
}

  1. 实现commit
代码语言:javascript复制
// cvuex.js
class Store {
  constructor(options) {
    this._mutations = options.mutations;
    // 响应化处理state
    this.state = new Vue({
      data: options.state,
    })
  }
  // store.commit('add', 1)
  /**
   * @type mutation的类型
   * @payload 参数
   */
  commit(type, payload) {
    const entry = this._mutations[type];
    if (entry) {
      entry(this.state, payload);
    }
  }
}

  1. 实现dispatch
代码语言:javascript复制
// cvuex.js
class Store {
  constructor(options) {
    this._mutations = options.mutations;
    this._actions = options.actions;
    // 响应化处理state
    this.state = new Vue({
      data: options.state,
    })
    // 绑定commit、dispatch的上下文为store实例
    this.commit = this.commit.bind(this);
    this.dispatch = this.dispatch.bind(this);
  }
  commit(type, payload) {
    const entry = this._mutations[type];
    if (entry) {
      entry(this.state, payload);
    }
  }
  dispatch(type, payload) {
    const entry = this._actions[type];
    if (entry) {
      entry(this, payload);
    }
  }
}

  1. 实现getters
代码语言:javascript复制
class Store {
  constructor(options) {
    // ...
    this._wrappedGetters = options.getters;

    const computed = {};
    this.getters = {};
    const store = this;
    Object.keys(this._wrappedGetters).forEach(key => {
      // 获取用户定义的getter
      const fn = store._wrappedGetters[key];
      // 转换为computed可以使用的无参数形式
      computed[key] = function() {
        return fn(store.state);
      }
      // 为getters定义只读属性
      Object.defineProperty(store.getters, key, {
        get: () => store._vm[key]
      });
    })
    this._vm = new Vue({
      data: {
        // 加两个$$ vue创建的时候不会做代理,对外隐藏
        $$state: options.state,
      },
      computed
    });
  }
  // ...
}

0 人点赞