# Gerenciamento de Estado

# Implementação Oficial Estilo Flux

Grandes aplicações podem frequentemente crescer em complexidade, devido à múltiplas partes do estado da aplicação espalhadas em vários componentes e em interações entre eles. Para resolver esse problema, Vue oferece o Vuex (opens new window), nossa própria biblioteca de gerenciamento de estado inspirada na arquitetura Elm. Ele é também integrado ao vue-devtools (opens new window), permitindo uma navegação pelo histórico de mudanças de estado (opens new window) (time travel debugging) sem qualquer configuração inicial.

# Informação para Desenvolvedores React

Se você vem do React, deve estar se perguntando como o Vuex se compara ao Redux (opens new window), a implementação Flux mais popular do ecossistema. O Redux é agnóstico quanto à camada view, de forma que ele pode ser usado facilmente com Vue através de ligações simples (opens new window). O Vuex é diferente por saber que está em uma aplicação Vue. Isso permite uma melhor integração com Vue ao fornecer uma API mais intuitiva e uma melhor experiência de desenvolvimento.

# Gerenciamento de Estado Simples do Zero

Frequentemente as pessoas esquecem que a fonte de verdade de aplicações Vue são os objetos reativos data - uma instância Vue apenas direciona acesso à eles. Portanto, se você possui uma parte do estado que deveria ser compartilhado entre instâncias múltiplas, você pode usar um método reactive para tornar um objeto reativo.

const { createApp, reactive } = Vue

const sourceOfTruth = reactive({
  message: 'Olá'
})

const appA = createApp({
  data() {
    return sourceOfTruth
  }
}).mount('#app-a')

const appB = createApp({
  data() {
    return sourceOfTruth
  }
}).mount('#app-b')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="app-a">App A: {{ message }}</div>

<div id="app-b">App B: {{ message }}</div>
1
2
3

Agora, sempre que sourceOfTruth mudar, tanto appA e appB irão atualizar suas views automaticamente. Possuímos uma única fonte de verdade agora, porém a depuração vira um pesadelo. Qualquer dado pode ser modificado em qualquer parte de nossa aplicação a qualquer momento, sem deixar rastro algum.

const appB = createApp({
  data() {
    return sourceOfTruth
  },
  mounted() {
    sourceOfTruth.message = 'Adeus' // ambas aplicações irão renderizar "Adeus"
  }
}).mount('#app-b')
1
2
3
4
5
6
7
8

Para ajudar a resolver esse problema, podemos adotar o padrão store:

const store = {
  debug: true,

  state: reactive({
    message: 'Olá!'
  }),

  setMessageAction(newValue) {
    if (this.debug) {
      console.log('setMessageAction disparado com', newValue)
    }

    this.state.message = newValue
  },

  clearMessageAction() {
    if (this.debug) {
      console.log('clearMessageAction disparado')
    }

    this.state.message = ''
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Perceba que todas as ações que modificam o estado da store são colocadas dentro da própria store. Esse tipo de gerenciamento de estado centralizado facilita a compreensão de que tipo de mutações podem acontecer e como elas são disparadas. Agora, temos um log de mudanças para quando algo der errado.

Além disso, cada instância/componente pode ainda possuir e gerenciar seu estado privado:

<div id="app-a">{{sharedState.message}}</div>

<div id="app-b">{{sharedState.message}}</div>
1
2
3
const appA = createApp({
  data() {
    return {
      privateState: {},
      sharedState: store.state
    }
  },
  mounted() {
    store.setMessageAction('Adeus!')
  }
}).mount('#app-a')

const appB = createApp({
  data() {
    return {
      privateState: {},
      sharedState: store.state
    }
  }
}).mount('#app-b')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Gerenciamento de Estado

Dica

Você jamais deve substituir o objeto state original - os componentes e a store precisam compartilhar a referência para o mesmo objeto, de forma que as mutações sejam acompanhadas.

Ao desenvolvermos uma convenção em que componentes não devem modificar diretamente o estado pertencente à store, mas sim disparar eventos que comuniquem a store à realizar ações, nós chegamos na arquitetura Flux (opens new window). A vantagem dessa convenção é que podemos registrar todas as mudanças de estado e implementar auxiliares avançados de depuração, tais como logs de mutação, snapshots e repetição de histórico (history re-rolls) / navegação de histórico (time travel).

O que nos leva totalmente de volta ao Vuex (opens new window), então se você leu até aqui, provavelmente é hora de testá-lo!