Back to home

Getting Started with script setup in Vue 3

99 min read

Vue 3 brings a lot of exciting new features to the table, one of the most powerful being the Composition API. But the Composition API also came with its own syntax, <script setup>, designed to make your code more modular, readable, and maintainable. In this blog, we’ll take a closer look at how <script setup> works and how to utilize it effectively in your Vue applications.

Why Use <script setup>?

The <script setup> syntax simplifies Vue component development by eliminating boilerplate code, like the need for export default. It enables us to define variables, functions, and lifecycle hooks directly within the setup scope, making it easier to manage complex state and logic in a clean and efficient way.

Let's explore <script setup> with various examples and understand how it changes the way we work with Vue components.

Basic Usage

The core idea of <script setup> is straightforward: it allows us to define variables, functions, and even lifecycle hooks directly inside the setup function. Here’s a quick example to show how it works.

<template>
  <div>
    <p>Counter: {{ count }}</p>
    <button @click="increment">Increase</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';

// Define a reactive variable
const count = ref(0);

// Define a function to increment the counter
function increment() {
  count.value++;
}
</script>

In this example:

  • We used ref to create a reactive count variable.
  • The increment function can modify this reactive value, and it will automatically update the template.

Working with Reactive Data

In Vue 3, ref and reactive are essential to create reactive data within components:

  • ref is for primitive types like numbers or strings.
  • reactive is for more complex structures like objects or arrays.
import { ref, reactive } from 'vue';

const count = ref(0);               // Reactive primitive type
const user = reactive({              // Reactive object
  name: 'Alice',
  age: 25
});

Using ref and reactive in this way keeps your data reactive, meaning any changes to these values automatically reflect in your template.

Computed Properties and Watchers

Vue 3 provides computed for creating computed properties and watch for watching changes in reactive properties. Both of these are easy to use within <script setup>.

<script setup>
import { ref, computed, watch } from 'vue';

const count = ref(0);

const doubleCount = computed(() => count.value * 2); // Define a computed property

watch(count, (newVal, oldVal) => {
  console.log(`Count changed from ${oldVal} to ${newVal}`);
});
</script>

In this snippet:

  • doubleCount is a computed property that doubles the value of count.
  • watch allows us to listen for changes in count and take action accordingly.

Lifecycle Hooks

Vue 3 allows you to use lifecycle hooks in a much simpler way within <script setup>. Common hooks like onMounted and onUnmounted are available as straightforward functions.

<script setup>
import { onMounted, onUnmounted } from 'vue';

onMounted(() => {
  console.log('Component has been mounted');
});

onUnmounted(() => {
  console.log('Component is about to be unmounted');
});
</script>

These hooks work just as they do in the traditional Options API but are easier to use and read.

Using Props and Emits

In <script setup>, you can define props and emits easily. Vue 3 provides defineProps and defineEmits to declare these in a type-safe way.

<template>
  <button @click="handleClick">{{ label }}</button>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';

const props = defineProps({
  label: String
});

const emit = defineEmits(['click']);

function handleClick() {
  emit('click');
}
</script>

In this example:

  • defineProps declares label as a prop, making it available in the template.
  • defineEmits allows us to emit custom events like click to parent components.

Full Example Using <script setup>

Combining everything we've discussed, here’s a complete example of a Vue 3 component that demonstrates the power of <script setup>:

<template>
  <div>
    <h1>Welcome, {{ user.name }}!</h1>
    <p>Double Count: {{ doubleCount }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script setup>
import { ref, reactive, computed, watch, onMounted } from 'vue';

const count = ref(0);
const user = reactive({ name: 'Alice', age: 25 });

const doubleCount = computed(() => count.value * 2);

watch(count, (newVal) => {
  console.log(`Count is now: ${newVal}`);
});

function increment() {
  count.value++;
}

onMounted(() => {
  console.log('Component mounted, fetching user data...');
  // Simulate fetching user data
});
</script>

Key Benefits of Using <script setup>

  1. Code Organization: All variables and functions are available within the same scope, making it easier to track logic flow.
  2. Cleaner Syntax: Eliminates boilerplate like export default, making code concise and to the point.
  3. Improved Readability: Functions, data, and methods are all located in one place, improving code readability and reducing complexity.

Wrapping Up

Vue 3's <script setup> syntax is a game-changer, offering a streamlined and efficient way to work with the Composition API. It’s particularly helpful for organizing complex state, logic, and lifecycle management in a single file component.

This syntax removes boilerplate code and allows you to focus on what really matters: building components that are powerful, readable, and maintainable. Whether you’re working on a small project or a large-scale application, <script setup> is a tool worth adopting in your Vue 3 journey. Give it a try, and see how it transforms your development experience!