Vue 不使用Vuex的情况下进行状态管理

在封装自己的Vue ui库的时候,往往要封装一些比较复杂的组件,比如说table,form之类。这些组件由于功能繁杂,还涉及到子组件嵌套及通信,如果没有一套状态管理方案的话很容易导致代码难以阅读、难以维护、难以修改等问题,但引入vuex的话又过于沉重。鉴于业内已经有element-ui这样比较成熟的案例,我们可以看看element-ui是怎么在没有vuex的情况下进行状态管理的。

Element-ui主要以两种形式进行状态管理:provider和自定义store。provider比较简单,父组件将数据装入providder,子组件用inject进行接收。这种方法优点是拿来即用,十分简单。缺点是子组件无法修改数据。所有局限性还是比较大的。

第二种方法是封装自定义store。我们参考element-ui中table组件,element-ui首先定义了一个table-store.js文件,存放store:

const TableStore = function(table, initialState = {}) {
  if (!table) {
    throw new Error('Table is required.');
  }
  this.table = table;

  this.states = {
    ...
  }

TableStore.prototype.mutations = {
    ...
}

TableStore.prototype.actions = {
    ...
}

除了没有actions以外其他基本和vuex差不多。

element-ui写tableStore用的是es5语法,这里用一个异步设置msg字段的typescript案例来进行讲解:

export class TestStore {

  public states: IState = {
    msg: ''
  };

  public commit(action: string, ...args: any[]) {
    const mutations = this.mutations as any;
    if (mutations[action]) {
      mutations[action].apply(this, [this.states].concat(args));
    } else {
      throw new Error(`Action not found: ${action}`);
    }
  }

  public mutations = {
    setMsg(states: IState, msg: any) {
      states.msg = msg;
    }
  };
}

interface IState {
  msg: string
}

使用的时候先在父组件上挂载store并传递给子组件:

<template>
    <div class="home">
        <img alt="Vue logo" src="../assets/logo.png">
        <HelloWorld :store="store" />
        '
        <p>
            {{store.states.msg}}
        </p>
    </div>
</template>

<s cript lang="ts">
  import { Component, Vue } from 'vue-property-decorator';
  import HelloWorld from '@/components/HelloWorld.vue';
  import { TestStore } from '@/utils/testStore';

  @Component({
    components: {
      HelloWorld,
    }
  })
  export default class Home extends Vue {
    store: TestStore = new TestStore();
  }
</s cript>


然后子组件用props接受store,并提交setMsg操作:

<template>

</template>

<s cript lang="ts">
  import { Component, Prop, Vue } from 'vue-property-decorator';

  @Component({
  })
  export default class HelloWorld extends Vue {
    @Prop() private store!: any;

    public created() {
      setTimeout(() => {
        this.store.commit('setMsg', 'changed');
      }, 1000);
    }
  }
</s cript>

然后Home组件template中的msg就会在相应的时间更新。这样我们就实现了不依赖vuex进行状态管理。

posted on 2019-04-02 10:58  axel10  阅读(1937)  评论(0编辑  收藏  举报