🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

Guia completo do Vue 3 2026: API de composição, Pinia e Nuxt.js

⏱️4 min read  ·  829 words

Vue 3 com API de composição, gerenciamento de estado Pinia e Nuxt.js para full-stack – Vue é a segunda estrutura JavaScript mais popular em 2026, com uma excelente experiência de desenvolvedor. Este guia completo cobre a API de composição do Vue 3, sistema de reatividade e padrões de produção.

Configurar

# Create new project
npm create vue@latest my-app

# Choose: TypeScript, Vue Router, Pinia, ESLint, Prettier
cd my-app && npm install && npm run dev

API de composição

<!-- Counter.vue — script setup syntax (preferred) -->
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';

// ref — reactive primitive
const count = ref(0);
const name = ref('World');

// computed — derived state (cached)
const doubled = computed(() => count.value * 2);
const greeting = computed(() => `Hello, ${name.value}! Count: ${count.value}`);

// watch — side effects
watch(count, (newVal, oldVal) => {
  console.log(`Count changed: ${oldVal} → ${newVal}`);
  document.title = `Count: ${newVal}`;
});

// watchEffect — auto-tracks dependencies
watchEffect(() => {
  localStorage.setItem('count', count.value.toString());
});

// Lifecycle hooks
onMounted(() => {
  console.log('Component mounted!');
  count.value = parseInt(localStorage.getItem('count') || '0');
});

function increment() {
  count.value++;
}

function reset() {
  count.value = 0;
}
</script>

<template>
  <div class="counter">
    <h2>{{ greeting }}</h2>
    <p>Doubled: {{ doubled }}</p>
    <!-- v-model works with refs automatically -->
    <input v-model="name" placeholder="Your name" />
    <div>
      <button @click="increment">+1</button>
      <button @click="reset">Reset</button>
    </div>
  </div>
</template>

Objetos reativos com reativo()

<script setup lang="ts">
import { reactive, toRefs } from 'vue';

// reactive — for objects (no .value needed)
const state = reactive({
  count: 0,
  name: 'Alice',
  todos: [] as string[],
});

// Destructure with toRefs (maintains reactivity)
const { count, name } = toRefs(state);

// Mutate directly
function addTodo(text: string) {
  state.todos.push(text);
}
</script>

Componentes e adereços

<!-- UserCard.vue -->
<script setup lang="ts">
interface Props {
  user: {
    id: number;
    name: string;
    email: string;
    avatarUrl?: string;
  };
  isSelected?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  isSelected: false,
});

const emit = defineEmits<{
  select: [userId: number];
  delete: [userId: number];
}>();

function handleSelect() {
  emit('select', props.user.id);
}
</script>

<template>
  <div
    class="user-card"
    :class="{ 'user-card--selected': isSelected }"
    @click="handleSelect"
  >
    <img
      v-if="user.avatarUrl"
      :src="user.avatarUrl"
      :alt="user.name"
    />
    <div>
      <h3>{{ user.name }}</h3>
      <p>{{ user.email }}</p>
    </div>
    <button @click.stop="emit('delete', user.id)">Delete</button>
  </div>
</template>

Composables — ganchos personalizados

// composables/useUsers.ts
import { ref, computed } from 'vue';

interface User { id: number; name: string; email: string; }

export function useUsers() {
  const users = ref<User[]>([]);
  const loading = ref(false);
  const error = ref<string | null>(null);
  const searchQuery = ref('');

  const filteredUsers = computed(() =>
    users.value.filter(u =>
      u.name.toLowerCase().includes(searchQuery.value.toLowerCase())
    )
  );

  async function fetchUsers() {
    loading.value = true;
    error.value = null;
    try {
      const response = await fetch('/api/users');
      users.value = await response.json();
    } catch (e) {
      error.value = 'Failed to load users';
    } finally {
      loading.value = false;
    }
  }

  async function createUser(data: Omit<User, 'id'>) {
    const response = await fetch('/api/users', {
      method: 'POST',
      body: JSON.stringify(data),
      headers: { 'Content-Type': 'application/json' },
    });
    const newUser = await response.json();
    users.value = [...users.value, newUser];
  }

  return { users, loading, error, searchQuery, filteredUsers, fetchUsers, createUser };
}

// Usage in component
const { users, loading, error, searchQuery, filteredUsers, fetchUsers } = useUsers();
onMounted(fetchUsers);

Gestão do Estado de Pinia

// stores/userStore.ts
import { defineStore } from 'pinia';

export const useUserStore = defineStore('users', {
  state: () => ({
    users: [] as User[],
    currentUser: null as User | null,
    loading: false,
  }),

  getters: {
    activeUsers: (state) => state.users.filter(u => u.active),
    userCount: (state) => state.users.length,
  },

  actions: {
    async fetchUsers() {
      this.loading = true;
      try {
        this.users = await api.getUsers();
      } finally {
        this.loading = false;
      }
    },

    async createUser(data: CreateUserInput) {
      const user = await api.createUser(data);
      this.users.push(user);
      return user;
    },

    logout() {
      this.currentUser = null;
    }
  }
});

// In component
import { useUserStore } from '@/stores/userStore';
const store = useUserStore();
await store.fetchUsers();
console.log(store.userCount);
store.logout();

Vue vs React: quando escolher o Vue

  • Escolha Vue quando: Curva de aprendizado mais simples necessária, abordagem preferencial de modelo, equipe menor, migração gradual de jQuery/Vanilla JS
  • Escolha Reagir quando: Equipe grande, necessidade de gerenciamento de estado complexo, ecossistema Next.js, React Native para dispositivos móveis
  • Ambos são excelentespara a maioria dos aplicativos da web – a escolha geralmente se resume à familiaridade da equipe

Vue 3 em 2026 com configuração de script, API de composição e Pinia é uma estrutura madura e amigável ao desenvolvedor. A sintaxe do modelo é mais acessível do que JSX para muitos desenvolvedores, e a API Composition oferece potência total para componentes complexos. Para full-stack, combine com Nuxt.js para obter os mesmos ganhos de produtividade que Next.js para React.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা