v-bind:class not working with script setup and the composition API in Vue 3

Viewed 1452

I am using Vue 3, with the script setup and the composition API. I am coming from Svelte, so using the script setup really reminds me of the simplicity of Svelte.

But I'm confused as to why this isn't working.

I have this template code:

<template>
<form @submit.prevent="handleSignIn(email, password)">
...
<button type="submit" :class="{ 'is-loading': isLoading }">Log in</button>
...
</form>
</template>

And this script code:

<script setup lang="ts">
let email: string;
let password: string;
let isLoading: boolean;

const handleSignIn = async (email: string, password: string) => {
  isLoading = true;
  ...
};
</script>

But when clicking the button for the form, the is-loading class does not get applied. Why is that?

1 Answers

I just figured it out, the isLoading property isn't reactive.

It just gets rendered when the component loads for the first time, but then any changes to the variable after will not be reflected in the DOM.

To fix it we can import { ref } from 'vue' and use ref() which will mark that variable as reactive data. Under the hood, and new in Vue 3, Vue will create a Proxy.

Working example:

<script setup lang="ts">
import { ref } from 'vue'

const isLoading = ref(false)

let email: string;
let password: string;

const handleSignIn = async (email: string, password: string) => {
  isLoading.value = true;
  ...
};
</script>

Credits to the author of this blog post, if you want to read more about ref and reactivity in Vue 3.

https://www.danvega.dev/blog/2020/02/12/vue3-ref-vs-reactive/

Related