Hierarquia e paralelismo em máquinas XState

Resumen

Trabalhar com máquinas de estado fica muito mais poderoso quando aprendes a combinar hierarquias e paralelismo no XState. Esta abordagem permite criar máquinas filhas dentro de máquinas maiores e até executar várias máquinas em simultâneo, ideal para modelar fluxos complexos numa aplicação real.

Antes de avançar, vale a pena revisitar como ficou resolvido o desafio anterior, porque introduz padrões que vais reutilizar aqui.

Como resolver o desafio dos passageiros e do contexto?

No componente passengers já recebíamos o state, então a partir dele extraímos o contexto e mapeamos a matriz de passageiros para imprimir cada nome.

  • Extrair passengers de state.context.
  • Mapear o array e renderizar um <p> com key e o nome.
  • No evento cancel, adicionar uma ação cleanContext.
  • Dentro de cleanContext, fazer assign de selectedCountry como string vazia e passengers como array vazio.

Com estes dois ajustes, a vista mostra os passageiros e o contexto fica limpo ao cancelar.

O que faz a ação assign no XState? É a forma de atualizar o contexto de uma máquina. Recebe um objeto onde cada chave é uma propriedade do contexto e o valor é o novo dado a guardar.

O que é a hierarquia em máquinas de estado?

Uma hierarquia é simplesmente ter máquinas filhas dentro de uma máquina maior. Pensa numa máquina principal que pergunta «o cão está acordado?» com um estado de sono e outro de vigília. O estado de vigília não é uma caixa simples: contém os seus próprios estados e eventos internos.

Isso é uma máquina filha: vive dentro de um estado pai e só fica ativa enquanto esse estado pai estiver ativo [03:00].

Como navegar entre estados hierárquicos?

No Visualizer do XState, ao clicar em start, a máquina entra no estado search e ilumina-se por completo. Lá dentro arranca no estado inicial loading, e a partir daí podes disparar:

  • done, que leva ao estado success (final).
  • error, que leva a failure.
  • retry, que volta a loading.

E aqui vem o detalhe importante: mesmo que a máquina filha de pesquisa não tenha terminado, podes disparar continue e sair do estado search para ir aos passageiros. Quando sais do estado pai, a máquina filha deixa de estar ativa.

Como declarar uma máquina filha em código?

No projeto, criámos uma constante chamada fetchCountries que funciona como máquina filha. Tem o seu próprio estado inicial loading e os seus estados internos com transições.

Para a inserir dentro do estado search da máquina pai, usamos o spread operator: dentro do objeto search, fora do on, fora de tudo, colocamos ...fetchCountries. Com isso, o XState entende que essa configuração faz parte do estado search como máquina filha.

Como funciona o paralelismo no XState?

No paralelismo temos duas ou mais máquinas a correr lado a lado, sem que o que acontece numa afete a outra. Não é uma relação pai e filha: são máquinas simultâneas e independentes.

No Visualizer, uma máquina de ficheiros com processos de download e upload aparece com pontinhos à volta a indicar paralelismo. Podes terminar o download enquanto o upload nem sequer começou, e nada se quebra.

Quando devo usar máquinas paralelas em vez de hierárquicas? Usa paralelas quando os fluxos são independentes e podem progredir em simultâneo, como download e upload. Usa hierárquicas quando um fluxo só faz sentido dentro de outro, como o carregamento de dados dentro de uma pesquisa.

Qual é um bom exemplo mental para entender o paralelismo?

Imagina um cachorrinho. Podes modelar duas máquinas em paralelo:

  • Uma representa o movimento da cauda: a abanar ou parada.
  • Outra representa o movimento do corpo: a andar ou parado.

O cachorro pode andar e abanar a cauda, andar sem abanar, ou estar quieto sem abanar. Cada máquina complementa a outra, mas nunca a condiciona.

Como se declara uma máquina paralela em código?

O truque está em duas coisas dentro da configuração da máquina:

  • Definir type: 'parallel' para sinalizar ao XState que estamos a criar máquinas paralelas.
  • Em states, declarar cada região como um estado independente, neste caso upload e download.

Tanto upload como download têm o seu próprio initial e os seus estados internos. Isso faz com que ambas sejam máquinas completas a viver dentro da máquina maior dos ficheiros, sem interferirem entre si.

Com hierarquias e paralelismo na bagagem, abre-se um leque enorme para diagramar fluxos complexos e levá-los para o teu projeto. Conta nos comentários que fluxo da tua aplicação vais modelar primeiro com estas técnicas.