Create Vue 3 Apps with the Composition API — Custom Refs and Shallow Reactivity
Tags: javascript, webdev, vue, programming
Published: 2021-01-19 00:38:20

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

It lets us extract logic easily and not have to worry about the value of `this` in our code.

It also works better with TypeScript because the value of `this` no longer has to be typed.

In this article, we’ll look at how to create Vue 3 apps with the Composition API.

### `customRef`

We can use the `customRef` function to create a custom ref.

For instance, we can write:

```
<template>
  <div>
    <input v-model="text" />
    {{ text }}
  </div>
</template>

<script>
import { customRef } from "vue";

const useDebouncedRef = (value, delay = 200) => {
  let timeout;
  return customRef((track, trigger) => {
    return {
      get() {
        track();
        return value;
      },
      set(newValue) {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
          value = newValue;
          trigger();
        }, delay);
      },
    };
  });
};

export default {
  name: "App",
  setup() {
    return {
      text: useDebouncedRef("hello world"),
    };
  },
};
</script>
```

We create the `useDebounceRef` function that returns a custom ref created bu the `customRef` function.

It takes a callback with the `track` function to track the value.

And the setter calls `trigger` to trigger state updates.

We ser the `value` in the setter to `newValue` so that the items are updated.

### `markRaw`

We can call the `markRaw` function to mark an object so that it’ll never be converted to a proxy.

For instance, we can write:

```
<template>
  <div></div>
</template>

<script>
import { isReactive, markRaw, reactive } from "vue";

export default {
  name: "App",
  setup() {
    const foo = markRaw({});
    console.log(isReactive(reactive(foo)));
    return { foo };
  },
};
</script>
```

The console log logs `false` since we called `markRaw` to disable reactivity on the object we passed into it.

But if we mark one object as raw and we reference that object in another object, then they’ll be considered not to be equal even though they have the same reference:

```
<template>
  <div></div>
</template>

<script>
import { isReactive, markRaw, reactive } from "vue";

export default {
  name: "App",
  setup() {
    const foo = markRaw({
      nested: {},
    });

    const bar = reactive({
      nested: foo.nested,
    });

    console.log(foo.nested === bar.nested);
    return { foo };
  },
};
</script>
```

We set `bar.nested` to `foo.nested` , but the console log is `false` .

### `shallowReactive`

We can create a shallow reactive object with the `shallowReactive` function.

The reactive property is limited to the top-level properties of the object.

For instance, we can write:

```
<template>
  <div>
    <button @click="increment">increment</button>
    {{ state.foo }}
    {{ state.nested.bar }}
  </div>
</template>

<script>
import { isReactive, shallowReactive } from "vue";

export default {
  name: "App",
  setup() {
    const state = shallowReactive({
      foo: 1,
      nested: {
        bar: 2,
      },
    });

    const increment = () => {
      state.foo++;
      state.nested.bar++;
    };
    console.log(isReactive(state.nested.bar));
    return { state, increment };
  },
};
</script>
```

In the `increment` function, we increment both `state.foo` and `state.nested.bar` and they’ll both update in the template.

But when we log `state.nested.bar` with `isReactive` , we get `false` logged.

Since it’s not reactive, it won’t trigger watchers to run:

```
<template>
  <div>
    <button @click="increment">increment</button>
    {{ state.foo }}
    {{ state.nested.bar }}
  </div>
</template>

<script>
import { isReactive, shallowReactive, watch } from "vue";

export default {
  name: "App",
  setup() {
    const state = shallowReactive({
      foo: 1,
      nested: {
        bar: 2,
      },
    });

    const increment = () => {
      state.foo++;
      state.nested.bar++;
    };

    watch(state.nested.bar, (bar) => {
      console.log(bar);
    });

    return { state, increment };
  },
};
</script>
```

Then `watch` callback in the 2nd argument won’t run when `state.nested.bar` is updated.

### Conclusion

We can use various functions provided Vue 3’s composition API to create various kinds of reactive and non-reactive properties.