14 nov 2024
Thin composables pattern
Descobri essa semana que a minha forma preferida de trabalhar com composables tem um nome bonito, “thin composables pattern”.
A ideia é a seguinte: ao invés de ter toda a lógica de alguma feature dentro de um grande composable ou em um só lugar (numa tela, por exemplo), separamos a regra de negócio de um lado e uma camada fina (thin layer) de reatividade do outro. Ou seja, toda parte de negócio fica em um arquivo js/ts “puro” e a parte que lida com os aspectos específicos do Vue e de implementação fica em um composable menor, mantendo-o apenas orquestrando a parte reativa, ciclos de vida, propriedades computadas, watchers, etc, que serão usados dentro dos componentes ou de telas.
Isso nos concede uma boa organização de código e separação de responsabilidades. Cada parte trabalha com uma única coisa. O que mais gosto é utilizar vários composables (pequenas features) em uma tela, assim consigo organizar loaders, tratativa de erros e demais pontos específicos da aplicação. Como os composables podem trabalhar também com o ciclo de vida, ou seja, chamando funções como onMounted, isso abre ainda mais possibilidades de uso.
/* /composables/useNotes.ts */
interface UseNotes {
user: Ref<User | undefined>
}
export function useNotes({ user }: UseNotes) {
const services = useServices()
const logger = useLogger()
const loading = ref(true)
const notes = ref<Note[]>()
const getNotes = async () => {
if (!user.value) return
try {
loading.value = true
const response = await services.getNotes({ userId: user.value.id })
// if (!response) { createError() }
notes.value = response
} catch (error) {
logger(error)
} finally {
loading.value = false
}
}
onMounted(() => getNotes())
return { loading, notes }
}
Uma nota sobre SSR: no exemplo acima a função getNotes é chamada quando o composable é iniciado. Essa é uma ótima implementação para códigos rodando no cliente. Como a camada de serviço fica separada, podemos chamar direto a função (do serviço) dentro de um useAsyncData e utilizar de todo o poder do Nuxt para tratar isso no lado do servidor, tendo assim todos os benefícios do SSR. Isso tudo depende do caso de uso, mas fica simples mudar a implementação, caso necessário.
É a maneira mais elegante de trabalhar com Vue? Provavelmente não. Eu particularmente sempre usei assim (ou algo parecido com isso), e vi esse tipo de implementação ser citada em cursos e, mais recenetemente, nesse podcast, então acho que estou no caminho, não?
Como tudo na área de desenvolvimento, é só mais uma das milhares de maneiras de resolver os mesmos problemas.