Vue Composables

Run the following to create a workspace for your Vue components:

$bit
Copiedcopy
See command synopsis

The generated workspace includes workspace-level configuration and some other configuration files for your IDE.

The unique part of this generated workspace includes:

  • tsconfig.json and types/types.d.ts for Vue & TypeScript support in IDEs.
  • "teambit.generator/generator": { "envs": ["bitdev.vue/vue-env"] } in workspace.json for creating new components without specifying the env aspect manually.

If your workspace was generated in other ways, you can still manually add them on.

To learn how to initialize a Bit workspace on an existing project, see Add Bit to an existing project.

Create a Vue composable

Run the following to create a component using your env's vue-composable template:

$bit
Copiedcopy
See command synopsis
Component compilation

Run Bit's development server (bit start) or watch mode (bit watch) to compile modified components.

Implementation file

The main implementation file is use-counter.ts, which is a Vue composable. You can modify it to your needs.

/* @filename: use-counter.ts -*/

// the by-default generated code is actually an existing Vue composable
// from VueUse (https://vueuse.org/useCounter)

import { ref } from "vue";

export interface UseCounterOptions {
  min?: number;
  max?: number;
}

/**
 * Basic counter with utility functions.
 *
 * @see https://vueuse.org/useCounter
 * @param [initialValue=0]
 * @param {Object} options
 */
export function useCounter(initialValue = 0, options: UseCounterOptions = {}) {
  const count = ref(initialValue);

  const { max = Infinity, min = -Infinity } = options;

  const inc = (delta = 1) => (count.value = Math.min(max, count.value + delta));
  const dec = (delta = 1) => (count.value = Math.max(min, count.value - delta));
  const get = () => count.value;
  const set = (val: number) =>
    (count.value = Math.max(min, Math.min(max, val)));
  const reset = (val = initialValue) => {
    initialValue = val;
    return set(val);
  };

  return { count, inc, dec, get, set, reset };
}
CopiedCopy

Compositions

Verify that your component behaves as expected by rendering it in various relevant contexts and variations. For example, you can see another file named use-counter-basic.fixtures.vue as a basic composition which utilize useCounter in multiple buttons and the output of count.

<!-- @filename: use-counter-basic.fixtures.vue -->

<script setup lang="ts">
import { useCounter } from "./use-counter";
const { count, inc, dec, set, reset } = useCounter();
</script>

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="inc()">Increment</button>
    <button @click="dec()">Decrement</button>
    <button @click="inc(5)">Increment (+5)</button>
    <button @click="dec(5)">Decrement (-5)</button>
    <button @click="set(100)">Set (100)</button>
    <button @click="reset()">Reset</button>
  </div>
</template>
CopiedCopy

And this file is gathered and exported by use-counter.composition.ts.

// @filename: use-counter.composition.ts

import BasicMyCounter from "./use-counter-basic.fixtures.vue";

export { BasicMyCounter };
CopiedCopy

You can add other compositions by aurhoring additional components in *.fixtures.vue and exporting them from use-counter.composition.ts or other *.composition.* files.

Head to the component's 'Compositions' tab, to see your rendered compositions (run bit start if you don't have the workspace UI running, already).

Tests

Head over to your component's .spec.ts file to add automated testing. We recommend using your compositions as the base for your testings, with Vue Testing Library as the test utils.

For example:

// @filename: use-counter.spec.ts

import { render } from "@testing-library/vue";
import { BasicUseCounter } from "./use-counter.composition";

describe("BasicUseCounter", () => {
  it("should render", async () => {
    const { getByText, findByText } = render(BasicUseCounter);

    expect(getByText("Count: 0")).toBeTruthy();
    getByText("Increment (+5)").click();
    expect(await findByText("Count: 5")).toBeTruthy();
  });
});
CopiedCopy

Also see Testing docs for more information.

Documentation

You can modify use-counter.docs.md to document your component's API and usage. To learn Markdown syntax, see Markdown Guide.

For example:

---
labels: ['vue']
description: A useCounter composable.
---

Basic counter with utility functions.

## Basic Usage

```ts
import { useCounter } from "${componentId}";

const { count, inc, dec, set, reset } = useCounter();
```

## Usage with options

```ts
import { useCounter } from "${componentId}";

const { count, inc, dec, set, reset } = useCounter(1, { min: 0, max: 16 });
```
CopiedCopy

Use the composable in a Vue component

Import the Vue composable into a Vue component using its package name (whatever it is maintained in the same workspace or installed from a remote scope):

<!-- @filename: my-counter.vue -->

<script setup lang="ts">
import { useCounter } from "@my-org/my-scope.composables.use-counter";

defineProps({
  title: {
    type: String,
    default: "",
  },
});

const { count, inc } = useCounter();
</script>

<template>
  <button @click="inc()">
    {{ title }}: {{ count }}
  </button>
</template>

<style scoped>
button {
  color: blue;
}
</style>
CopiedCopy

Resources

There is an open source project called VueUse which is a comprehensive collection of Vue composables you can refer to before building your own composables.

To use it in your component, run the following command:

$bit
Copiedcopy
See command synopsis

Then, import the composable from @vueuse/core:

import { useLocalStorage, useMouse, usePreferredDark } from '@vueuse/core'

export default {
  setup() {
    // tracks mouse position
    const { x, y } = useMouse()

    // if user prefers dark theme
    const isDark = usePreferredDark()

    // persist state in localStorage
    const store = useLocalStorage(
      'my-storage',
      {
        name: 'Apple',
        color: 'red',
      },
    )

    return { x, y, isDark, store }
  },
}
CopiedCopy