Vue-cubit is a predictable state management library for Vue and heavily inspired by BLoC.
For vue@3:
yarn add @vue-cubit/core
For vue@2 + @vue/composition-api
yarn add @vue-cubit/core @vue/composition-api
// ./cubit.ts
import { Cubit } from "@vue-cubit/core";
class CounterCubit extends Cubit<number> {
constructor() {
super(0);
}
increment = () => {
this.emit(this.state + 1);
};
}
<!-- ./index.vue -->
<template>
<button type="button" @click="counterCubit.increment">
count is: {{ counterCubit.state }}
</button>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { CounterCubit } from "./cubit";
export default defineComponent({
name: "Counter",
setup: () => {
const counterCubit = new CounterCubit();
return { counterCubit };
},
});
</script>
// ./cubit.spec.ts
import { CounterCubit } from "./cubit";
import { cubitTest } from "@vue-cubit/core";
describe("CounterCubit", () => {
let todoCubit: CounterCubit;
beforeEach(() => {
todoCubit = new CounterCubit();
});
cubitTest<CounterCubit, number>("emits [] when nothing added", {
build: () => todoCubit,
expect: () => [],
});
cubitTest<CounterCubit, number>("emits [1] when invoke increment", {
build: () => todoCubit,
act: (cubit) => {
cubit.increment();
},
expect: () => [1],
});
});
yarn add @vue-cubit/replay-plugin
<!-- ./index.vue -->
<template>
<button type="button" @click="counterCubit.increment">
count is: {{ counterCubit.state }}
</button>
+ <button :disabled="counterCubit.canUndo === false" @click="counterCubit.undo">Undo</button>
+ <button :disabled="counterCubit.canRedo === false" @click="counterCubit.redo">Redo</button>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { CounterCubit } from "../cubit";
+ import { ReplayPlugin } from "@vue-cubit/replay-plugin";
export default defineComponent({
name: "Counter",
setup: () => {
- const counterCubit = new CounterCubit();
+ const counterCubit = new CounterCubit().use(new ReplayPlugin<number>());
return { counterCubit };
},
});
</script>
yarn add @vue-cubit/hydrated-plugin
<!-- ./index.vue -->
<template>
<button type="button" @click="counterCubit.increment">
count is: {{ counterCubit.state }}
</button>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { CounterCubit } from "../cubit";
+ import { HydratedPlugin } from "@vue-cubit/hydrated-plugin";
export default defineComponent({
name: "Counter",
setup: () => {
- const counterCubit = new CounterCubit();
+ const counterCubit = new CounterCubit().use(
+ new HydratedPlugin<number>("counterCubit", localStorage, {
+ fromJson: JSON.parse,
+ toJson: JSON.stringify,
+ })
+ );
return { counterCubit };
},
});
</script>
-
Cubit's state is reactive.
-
Update state with emit method inherited from cubit.
- Use state with
v-model
is fine, but DO NOT directly modify state elsewhere.
-
Use
@vue-cubit/hydrated-plugin
to automatically persists and restores states. -
Use
@vue-cubit/replay-plugin
to adds the ability to undo and redo.