Vue3: como declarar estados reativos
Angela Caldas
Posted on March 6, 2024
Em uma Single Page Application (SPA), a reatividade é a capacidade que o aplicativo tem de responder dinamicamente a alterações em seus dados, atualizando partes da página sem a necessidade de recarregá-la do zero.
Quando o Vue identifica mudanças em seus estados, ele usa o virtual DOM para re-renderizar a interface e garantir que ela sempre esteja atualizada, tornando o processo o mais rápido e eficiente possível.
Existem diferentes formas de declarar estados reativos em uma aplicação Vue, que podem variar dependendo da API que estiver em uso (Options ou Composition), além dos tipos de dados em si. E é isso que vamos abordar nesse artigo!
Sumário
Dados reativos com Options API:
Data properties
Computed Properties
Diferença entre métodos e propriedades computadas
Dados reativos com Composition API
ref()
reactive()
Limitações do reactive()
computed()
Em resumo...
Dados reativos com Options API
Data properties
Com a Options API, declaramos estados reativos de um componente através das propriedades de dados (data properties), utilizando o método data
para tal. Esse método retorna um objeto com todos os estados reativos e seus valores.
<script>
export default {
data () {
counter: 0
}
}
</script>
No exemplo acima, counter
é um dado reativo e, caso seja alterado, a interface atualizará automaticamente para refletir as alterações.
Para vermos a reatividade em ação, vamos criar um método (ou função) que modifica o valor de counter
cada vez que clicarmos um botão.
<script>
export default {
data () {
counter: 0
},
methods: {
increaseCounter() {
this.counter++
}
}
}
</script>
Veja que, ao clicar no botão, o valor de counter
é automaticamente atualizado na interface.
É importante que todos os dados reativos a serem utilizados no componente sejam declarados na opção data
mesmo que ainda não tenham um valor definido, pois eles serão instanciados no componente assim que ele for criado (proporcionando o uso de this
em métodos e ciclos de vida).
Caso precise iniciar um estado sem valor definido, você pode usar undefined
, null
ou agum outro valor que sirva de placeholder (como uma string vazia, por exemplo).
Computed Properties
As propriedades computadas (computed properties) são utilizadas quando precisamos fazer cálculos ou outras lógicas baseadas em data properties
de forma passiva. Ou seja, quando um dado reativo é alterado, todas as propriedades computadas que dependem desse dado também são atualizadas. É como se elas fossem funções formatadoras de variáveis.
Para declarar propriedades computadas, usamos a sintaxe de função dentro da opção computed
. Essa função deve sempre retornar um valor.
<script>
export default {
// Código oculto
computed: {
doubleCounter() {
return this.counter * 2
}
}
}
</script>
Note que não utilizamos a sintaxe de arrow function em nossa propriedade computada, pois estas não possuem this
em seu contexto, impossibilitando que possamos acessar nossas data properties.
A propriedade computada acima retorna sempre o dobro do valor de counter
. Podemos ver em nossa aplicação que, sempre que counter
for modificado, o valor de doubleCounter
é automaticamente atualizado:
O mesmo resultado poderia ser obtido diretamente no template
do nosso componente inserindo a lógica dentro da interpolação ({{ }}
também chamada de mustache, nosso bom "bigodinho").
<template>
<p>The double of counter is: {{ doubleCounter }}</p>
<!-- VIRARIA -->
<p>The double of counter is: {{ counter * 2 }}</p>
<template>
Dessa forma, nossa aplicação funcionaria da mesma maneira. Porém, em aplicações maiores essas lógicas podem ficar bem mais complexas e, com o uso das propriedades computadas, podemos deixar nosso template
mais fácil de entender e nosso código mais organizado.
Diferença entre métodos e propriedades computadas
É fácil perceber que a mesma lógica de doubleCounter
poderia ser alcançada através de um método em vez de uma propriedade computada, concorda?
<template>
<p>{{ doubleCounter() }}</p>
<template>
<script>
// código oculto
methods: {
doubleCounter() {
return this.counter * 2
}
}
</script>
Com o código acima, poderíamos facilmente obter o mesmo resultado. E por que não optamos por essa alternativa? Porque propriedades computadas são armazenadas em cache com base nos dados reativos dos quais depende.
E o que isso significa?
Significa que, enquanto counter
não sofrer modificação, doubleCounter
também não mudará e sempre retornará o último resultado computado independente de quantas vezes você re-renderizar o seu componente. Por outro lado, métodos sempre serão executados quando o componente for re-renderizado, mesmo que nosso dado reativo counter
não mude.
Porque precisamos de caching? Imagine que temos uma enorme lista como propriedade computada, que faz loops em um array enorme e faz vários cálculos. E então temos outras propriedades computadas que dependem dessa lista. Sem caching, executaríamos o getter da lista muito mais vezes que o necessário (quando podemos executar apenas quando a lista sofrer alterações)! — Extraído da documentação do Vue.
Dessa forma, vamos usar métodos apenas quando não precisarmos de caching! 😉
Dados reativos com Composition API
No Vue 3, a reatividade é alcançada através do sistema conhecido como "Reatividade Proxy-based", que cria proxies em torno dos objetos de dados e permitem interceptar operações de leitura (get) e escrita (set) nas propriedades desses objetos. Este sistema é uma evolução do sistema de reatividade utilizado nas versões anteriores do Vue (que utilizavam Object. defineProperty
), proporcionando um desempenho mais eficiente e com menos limitações.
Dessa forma, devido a essa atualização, com a Composition API temos formas diferentes de declarar estados reativos. Aqui saem as data properties e entram as funções ref()
e reactive()
na jogada!
ref()
Para declarar dados reativos usando a função ref()
, devemos usar a sintaxe de declaração de variáveis com const
. ref()
é comumente utilizado para estados com tipos primitivos (como string
, number
, boolean
, etc.). Vamos utilizar o mesmo exemplo de counter
:
<script setup>
import { ref } from "vue";
const counter = ref(0);
const increaseCounter = () => {
counter.value++;
};
</script>
Quando estudamos as diferenças entre Options e Composition API, vimos que precisamos importar as funções nativas do Vue que vamos utilizar em nosso componente. Então, começamos importando ref
e usando-o em nossa variável counter
para englobar o valor inicial do nosso estado.
Para alterar o valor de counter
, criamos uma arrow function que modifica a propriedade .value
da nossa ref
. Essa propriedade é criada automaticamente pelo sistema de reatividade do Vue 3, não sendo necessário declará-la ao criar nosso estado com ref()
. E é essa propriedade que permite que o Vue detecte se um estado foi acessado ou alterado.
Note que, quando usamos nosso estado computado diretamente no template
, não precisamos usar a propriedade .value
.
reactive()
Reactive é a segunda forma que o Vue disponibiliza para declaração de dados reativos. Diferente de ref
, que engloba o valor do dado em um objeto interno com a propriedade .value
, a função reactive()
torna dados do tipo objeto em um objeto reativo. Logo, reactive()
tem a limitação de não aceitar strings, números e booleans.
Ainda mantendo o exemplo de counter
, podemos refatorar nosso código para utilizar reactive()
:
<script setup>
import { reactive} from "vue";
const state = reactive({ counter: 0 });
const increaseCounter = () => {
state.counter++;
};
</script>
No código acima, nossa variável state
agora recebe um objeto { counter: 0 }
como dado reativo. Nesse caso, se quisermos alterar o valor de counter
, podemos acessar diretamente a chave counter
dentro do objeto state
no nosso método increaseCounter
.
Note que em nosso template
também precisamos acessar diretamente state.counter
para que seu valor seja renderizado corretamente na tela.
Limitações do reactive()
Como dito mais acima, a primeira limitação da função reactive()
é não aceitar string
, number
e boolean
. Sendo assim, essa função deve ser usada apenas para dados do tipo objeto (como os próprios objetos, arrays e coleções, como Map
e Set
).
Também não é possível reatribuir um novo valor ao mesmo objeto reativo, ou seja, não é possível substituir o objeto inteiro por um outro objeto, pois o sistema de reatividade do Vue trabalha diretamente com o acesso às propriedades.
// Não é possível reatribuir o valor de state
let state = reactive({ count: 0 })
state = reactive({ count: 1 })
O uso de reactive()
também não permite desestruturação, pois a referência de conexão da reatividade é perdida:
const state = reactive({ count: 0 })
// count é desconectado de state.count quando desestruturado
let { count } = state
computed()
O uso de propriedades computadas mantém o mesmo propósito visto anteriormente: executar cálculos e lógicas de forma passiva de acordo com a mudança detectada em uma ref()
ou reactive()
.
Porém, com a Composition API, temos uma sintaxe diferente para a criação dessas propriedades computadas: computed()
agora é uma função que recebe como parâmetro outra função e retorna uma ref
computada. Vamos ao exemplo:
<script setup>
import { ref, computed } from "vue";
// código ocultado
const doubleCounter = computed(() => {
return counter.value * 2;
});
</script>
No código acima, declaramos nossa propriedade computada como uma variável e usamos a função computed()
para englobar uma arrow function que contém nossa lógica.
Em resumo...
Exploramos as nuances de criar dados reativos no Vue, mergulhando na sintaxe da Options API e da Composition API. Ao desbravar a criação de propriedades de dados e computadas, tocamos na essência das Options API, onde a familiaridade com data properties e computed properties se revela crucial. Além disso, nos aventuramos na Composition API, onde ref, reactive e computed oferecem ferramentas poderosas para estruturar lógica reativa de forma mais modular e concisa.
Agora que você já sabe como declarar dados reativos, ampliando seu repertório para lidar com a reatividade no Vue e construir aplicações mais robustas e eficientes, você está pronto para elevar sua experiência de desenvolvimento Vue para novos patamares. Experimente, inove e desfrute da jornada reativa!
Posted on March 6, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.