How to order and structure the features in a Composition API component
In the Composition API of Vue 3, features such as refs
, computed
, watch
, methods
and lifecycle hooks can be organized in a logical and readable way. Since the Composition API groups logic by features rather than by options (as in the Options API), organizing them well is key to maintaining clean and scalable code.
Here’s how you can order and structure the features in a Composition API component for better readability and maintainability.
General Recommended Order
- Imports: External libraries, composables, or helpers should be imported at the top.
- Setup Function: This is where everything is defined in Composition API components.
- Reactive State:
ref()
andreactive()
should come first, as they define the state. - Computed Properties: Add computed values next because they depend on reactive state.
- Methods/Functions: These should come after computed properties as they might use both state and computed values.
- Watchers: These follow methods as they might depend on reactive data or computed properties.
- Lifecycle Hooks: Lifecycle hooks (
onMounted
,onUnmounted
, etc.) come last as they depend on the defined state and methods.
3. Return Statement: Finally, return all reactive state, computed properties, and methods to expose them to the template.
Example of Feature Order in Composition API
<script setup>
import { ref, reactive, computed, watch, onMounted } from 'vue';
// 1. Reactive State (ref, reactive)
const count = ref(0);
const user = reactive({
name: 'John Doe',
age: 30,
});
// 2. Computed Properties
const isAdult = computed(() => user.age >= 18);
const greetingMessage = computed(() => `Hello, ${user.name}`);
// 3. Methods (Functions)
const increment = () => {
count.value++;
};
const updateUserAge = (newAge) => {
user.age = newAge;
};
// 4. Watchers
watch(count, (newCount) => {
console.log(`Count changed to: ${newCount}`);
});
// 5. Lifecycle Hooks
onMounted(() => {
console.log('Component is mounted');
});
// 6. Return reactive state, computed properties, and methods
// Exposing these to be used in the template
return {
count,
user,
isAdult,
greetingMessage,
increment,
updateUserAge,
};
</script>
Explanation of the Order
- Reactive State:
ref
andreactive
are placed at the top since they define the base state of the component. - Computed Properties: These are placed right after reactive state because they are derived from that state.
- Methods: Functions that manipulate state or perform actions come next. These may rely on the state or computed properties.
- Watchers: These track changes to reactive state or computed values, so they should come after the data and computed properties are defined.
- Lifecycle Hooks: Placing lifecycle hooks at the end ensures that the component logic is fully defined before they are used.
Organizing Larger Components
For larger components, organizing features by their logical function can help improve readability. Here are some tips:
- Group related logic together: If you’re working with forms, group all the state, computed properties, methods, and watchers related to the form together.
- Use comments or sections: For better clarity, you can add comments to group different sections of your component.
- Extract logic into composables: For reusable logic or large chunks of logic, consider extracting them into separate composable functions.
Example of Grouping by Logical Feature
<script setup>
import { ref, reactive, computed, watch, onMounted } from 'vue';
// ======= State =======
const count = ref(0);
const user = reactive({
name: 'John Doe',
age: 30,
});
// ======= Computed =======
const isAdult = computed(() => user.age >= 18);
const greetingMessage = computed(() => `Hello, ${user.name}`);
// ======= Methods =======
const increment = () => {
count.value++;
};
const updateUserAge = (newAge) => {
user.age = newAge;
};
// ======= Watchers =======
watch(count, (newCount) => {
console.log(`Count changed to: ${newCount}`);
});
// ======= Lifecycle Hooks =======
onMounted(() => {
console.log('Component is mounted');
});
// Return reactive state, computed properties, and methods
return {
count,
user,
isAdult,
greetingMessage,
increment,
updateUserAge,
};
</script>
This approach keeps the component structure clean and easy to follow.
Advanced Tips for Large Components
- Break Logic into Composables: If a component gets too large, extract some logic into separate files (composables).
Example composable:
// useCounter.js
import { ref } from 'vue';
export function useCounter() {
const count = ref(0);
const increment = () => {
count.value++;
};
return { count, increment };
}
2. Use Helper Functions: If the logic is reused across components, encapsulate common logic in helpers.
3. Feature-based Grouping: Group logic by feature, such as state management for specific sections (e.g., form handling, fetching data, etc.), so it’s easier to navigate the code.
Conclusion
In Vue 3 Composition API, organizing features effectively is important for readability and maintainability. The general order of reactive state, computed properties, methods, watchers, and lifecycle hooks should provide a logical structure. For larger components, breaking down the logic into groups or composables can further improve code clarity.