Comprehensive Guide to Using Props in Vue 3 <script setup>

Dec 08, 2025 · Programming · 10 views · 7.8

Keywords: Vue 3 | <script setup> | Props | defineProps | Reactive Programming

Abstract: This article provides an in-depth exploration of how to declare and use props in Vue 3's <script setup> syntax. By analyzing the functionality of the defineProps() function, it details two primary declaration methods: option-based and type-based (for TypeScript). The discussion includes how to safely access props in asynchronous functions using toRefs(), with complete code examples to help developers avoid common pitfalls and enhance code maintainability and type safety.

In Vue 3's Composition API, the <script setup> syntax offers a more concise way to write component logic without explicitly exporting a setup function. However, this new syntax handles props differently from traditional approaches, requiring careful attention from developers. Based on best practices, this article thoroughly explains how to effectively declare and use props in <script setup>, ensuring code clarity and maintainability.

Basic Declaration and Access of Props

In <script setup>, props declaration relies on the defineProps() function. This function accepts one argument, which can be an options object or a type definition, and returns a reactive object containing all declared props. For example, for a simple string prop "no", it can be declared as follows:

<script setup>
import { defineProps } from "vue";

const props = defineProps({
  no: String,
});
</script>

Here, defineProps() defines the props accepted by the component and returns a reactive object props. In the template, it can be accessed directly via {{ no }}, but in script logic, it must be referenced through props.no. This ensures the reactivity of props, but direct destructuring may lead to loss of reactivity, so it should be handled with caution.

Using Props in Asynchronous Functions

In real-world development, props are often used in asynchronous functions, such as making API requests. To maintain reactivity, it is recommended to use toRefs() for destructuring props. Below is a complete example:

<template>
  <TopNavbar title="room" />
  <div>
    {{ no }}
  </div>
</template>

<script setup>
import TopNavbar from "@/layout/TopNavbar.vue";
import { defineProps, reactive, toRefs } from "vue";

const props = defineProps({
  no: String,
});

const { no } = toRefs(props);

const state = reactive({
  room: {},
});

const init = async () => {
  const { data } = await getRoomByNo(no.value);
  console.log(data);
};

init();
</script>

In this example, toRefs(props) converts the props object into a collection of refs, and the destructured no is a ref accessed via no.value. This ensures that reactivity is not lost during asynchronous operations, preventing potential bugs. If props.no is used directly, changes might not be tracked correctly in asynchronous contexts.

Type Declarations in TypeScript

For projects using TypeScript, defineProps() supports type-based declarations, offering stricter type checking. This method passes type definitions via generic parameters, for example:

<script setup lang="ts">
import { defineProps } from "vue";

const props = defineProps<{
  no: string,
}>();
</script>

The benefit of type declarations is enhanced code reliability and developer experience, with IDEs providing better autocompletion and error detection. However, early versions did not support default values in type declarations, but this can now be achieved using the withDefaults() helper function:

<script setup lang="ts">
interface Props {
  msg?: string;
}

const props = withDefaults(defineProps<Props>(), {
  msg: "hello",
});
</script>

This combines type safety with default value settings, representing a recommended best practice. Developers should choose the declaration method based on project needs: option-based is simpler for JavaScript projects, while type-based is more rigorous for TypeScript environments.

Common Issues and Best Practices

When handling props in <script setup>, several key points must be noted. First, avoid destructuring props directly without using toRefs(), as this may break reactivity. Second, in asynchronous functions, always access prop values via the .value property of refs. Additionally, for complex components, consider centralizing props declarations to improve readability.

From a performance perspective, defineProps() is processed at compile time, adding no runtime overhead. Combined with Vue 3's reactive system, props usage is efficient and flexible. Developers should leverage these features to write more robust component code.

In summary, props handling in <script setup> is simplified by defineProps(), but reactivity maintenance requires attention. Through the examples and analysis in this article, developers can master core techniques to enhance productivity in Vue 3 projects.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.