Comprehensive Guide to Vue Component Writing Styles: Options API, Composition API, Setup Syntax Sugar, Render Functions, and JSX
This article systematically introduces the many ways to write Vue components—including the classic Options API, the modern Composition API with setup syntax sugar, hand‑written render functions using h or createVNode, and various JSX techniques—explaining their principles, code examples, and when to choose each approach.
Introduction
Vue 3’s official documentation mentions two primary component styles: the Options API and the Composition API. In practice, Vue components can be written in many more ways, all built on the same underlying system. Understanding these styles helps you read the docs, interpret ambiguous APIs, and explore Vue’s source code.
Setup Syntax Sugar
The setup syntax sugar is the most common pattern in Vue 3. A component is placed in a single .vue file with <template> , <script setup> , and <style> sections. The example below shows a simple component that defines a ref and renders it.
<template>
<div>{{ name }}</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
const name = ref("天气好");
</script>
<style scoped></style>In App.vue the component is imported and used like any other component.
// App.vue
<template>
<User />
</template>
<script setup lang="ts">
import User from "./User.vue";
</script>
<style scoped></style>Vue 2 Options‑style Writing
Classic Options API
The classic Vue 2 style exports a plain object containing data , methods , etc.
<template>
<div>{{ name }}</div>
</template>
<script lang="ts">
export default {
data: () => ({
name: "天气好"
})
};
</script>
<style></style>defineComponent Helper
Using defineComponent provides better type inference while still exporting a plain object.
<template>
<div>{{ name }}</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
data: () => ({
name: "天气好"
})
});
</script>
<style></style>Vue 3 Options‑style Writing
Vue 3 introduces a new setup option inside the Options API, allowing the use of Composition API features such as ref and reactive while keeping the familiar data / methods structure.
<template>
<div>{{ name }}</div>
</template>
<script lang="ts">
export default {
setup() {
return { name: "天气好" };
}
};
</script>
<style></style>When defineComponent is used, the setup parameters are typed, improving IDE support.
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup(props, context) {
return { name: "天气好" };
}
});
</script>Hand‑written Render Functions
Templates are compiled to render functions. You can bypass the template and write a render function directly, using either h (alias of createVNode ) or JSX.
<script lang="ts">
import { defineComponent, h } from "vue";
export default defineComponent({
data: () => ({ name: "天气好" }),
render() {
return h("div", this.name);
}
});
</script>Setup Returning a Render Function
Instead of returning an object for the template, setup can return a render function.
<script lang="ts">
import { defineComponent, h, ref } from "vue";
export default defineComponent({
setup() {
const name = ref("天气好");
return () => h("div", name.value);
}
});
</script>Note that ref values must be accessed via .value inside h because automatic unwrapping only works in templates.
Using JSX
JSX inside a render function
JSX can replace h for a more concise syntax.
<script lang="tsx">
import { defineComponent } from "vue";
export default defineComponent({
data() { return { name: "天气好" }; },
render() {
return (<>
{this.name}
);
}
});
</script>JSX returned from setup
<script lang="tsx">
import { defineComponent, ref } from "vue";
export default defineComponent({
setup() {
const name = ref("天气好");
return () => (<>{name.value});
}
});
</script>Directly exporting a JSX object
You can export a JSX element directly, which is useful for tiny reusable pieces.
<script lang="tsx">
import { ref } from "vue";
const name = ref("天气好");
const User = <>{name.value};
export default User;
</script>Functional Components (FC)
Vue allows function‑style components that receive props as arguments.
<script lang="tsx">
import { ref } from "vue";
export default function User(props: { "user-name": string }) {
const name = ref("天气好");
return <>{props["user-name"]};
}
</script>Standalone JSX/TSX Files
All the above patterns can be placed in .tsx files without the surrounding <script> block, making them look more like pure JSX components.
// User.tsx
import { ref, defineComponent } from 'vue';
export default defineComponent({
setup() {
const name = ref('天气好');
return () => (<>{name.value});
}
});Functional components can also be written as plain functions and exported directly.
// User.tsx
import { ref } from 'vue';
export default function User(props) {
const name = ref('天气好');
return <>{props.userName};
}
User.props = { userName: String };Conclusion
Vue’s core remains option‑based, but Vue 3 adds the setup option and syntax sugar, allowing most logic to live inside setup . While templates are the recommended way to describe UI, hand‑written render functions and JSX give you fine‑grained control when needed.
Personal Opinion
Prefer the setup syntax sugar for new code.
When using the Options API, wrap the component with defineComponent for better type inference.
If JSX is required, use the Options API with setup returning a JSX render function inside a .vue file rather than moving the component to a separate .tsx file.
For extensive functional‑component use, consider React instead of Vue.
References
Rendering Functions & JSX | Vue.js
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.