2

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
  • I think you should also return the isLoading from setup Commented Oct 22, 2021 at 11:16

1 Answer 1

3

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/

Not the answer you're looking for? Browse other questions tagged or ask your own question.