Imported from wesleyara/PersonalGrowth.Frontend (
.claude/skills/new-composable/SKILL.md). Install upstream withnpx skills add wesleyara/PersonalGrowth.Frontend --skill new-composable. Copyright stays with the author.
Criar novo composable
Segue as convenções documentadas em docs/context/06-file-structure-conventions.md e docs/context/05-architecture.md (divisão Pinia vs useStorage).
Passos
-
Local do arquivo: pasta própria
src/composables/useX/, nome emcamelCaseprefixado comuse(ex:composables/useHabitFrequency/,composables/useStreak/), contendo:composables/ useX/ index.ts tests/ useX.spec.ts models/ # opcional, só se houver tipos locais ao composable -
Antes de criar, decida se é realmente um composable ou deveria ser um store Pinia (use a skill
/new-storenesse caso):- Composable: lógica reativa reutilizável sem necessidade de estado compartilhado entre componentes distantes na árvore, ou wrapper fino sobre
useStoragedo VueUse para uma preferência simples de UI (tema, filtro selecionado). - Store Pinia: dados de domínio que precisam ser acessados/mutados por múltiplos componentes não relacionados (hábitos, check-ins, tags, gamificação).
- Composable: lógica reativa reutilizável sem necessidade de estado compartilhado entre componentes distantes na árvore, ou wrapper fino sobre
-
Estrutura do
index.ts:import { computed, ref } from "vue"; export function useX() { const state = ref(); const derived = computed(() => { // lógica derivada }); function action() { // lógica de ação } return { state, derived, action }; }- Se o composable envolve lógica de negócio pura (cálculo de streak, avaliação de
FrequencyRule), extraia a função pura parasrc/utils/(ex:frequency-evaluator.ts) e deixe o composable como uma casca reativa fina em cima dela — facilita testar a lógica isoladamente sem montar um componente Vue. - Se o composable precisa de tipos próprios além dos já definidos em
src/types/, adicione-os lá, não inline no composable.
- Se o composable envolve lógica de negócio pura (cálculo de streak, avaliação de
-
Composables de preferência de UI (ex:
useTheme): usaruseStoragedo VueUse diretamente, com uma chave delocalStorageclara e namespaced (ex:trackgrowth:theme), para não colidir com as chaves usadas pelopinia-plugin-persistedstatedos stores de domínio. -
Após criar
index.ts, criartests/useX.spec.tscobrindo o estado/derivações/ações expostos — não é opcional. Depois, rodeyarn lint:fix.
O que não fazer
- Não crie um composable que só reexporta um store Pinia sem adicionar lógica — importe o store diretamente no componente nesse caso.
- Não guarde dados de domínio (hábitos, check-ins) dentro de um composable com
useStorage— isso é responsabilidade dos stores Pinia persistidos, que oferecem getters/ações compartilhados.
