Hi everyone š,
Iām in the process of refactoring my Nuxt 3 app and wanted to get some feedback on best practices. Right now, a lot of my components directly handle data fetching and business logic, but Iād like to move those responsibilities into composables for better testability and reusability.
The idea is to keep components as ādumbā UI pieces and move logic elsewhere. For example:
<!-- components/UserList.vue -->
<script setup lang="ts">
const { users, pending, error, refresh, activeUsers, findUserById } = useUsers()
</script>
<template>
<div>
<div v-if="pending">Loading...</div>
<div v-else-if="error">{{ error.message }}</div>
<ul>
<li v-for="user in activeUsers" :key="user.id">
{{ user.name }}
</li>
</ul>
<button @click="refresh">Reload</button>
<div>
<strong>Lookup user 1:</strong>
{{ findUserById(1)?.name ?? 'Not found' }}
</div>
</div>
</template>
// composables/useUsers.ts
import { computed } from 'vue'
export function useUsers() {
const { data: users, pending, error, refresh } = useFetch('/api/users')
// Example computed property
const activeUsers = computed(() =>
(users.value ?? []).filter(u => u.isActive)
)
// Example function
function findUserById(id: number) {
return (users.value ?? []).find(u => u.id === id)
}
return { users, pending, error, refresh, activeUsers, findUserById }
}
This way I can test my data-fetching + derived state + helper functions in isolation without rendering the full component tree.
My questions for the community:
- Is moving fetching + business logic into composables a sound approach in Nuxt 3?
- Are there pitfalls I should be aware of (SSR concerns, test complexity, etc.)?
- Do you follow a different pattern for separating logic from UI?
Appreciate any insights or examples of how you structure this in larger Nuxt apps š