stamatios
← Voltar ao feed
Trilhos de rotas, cache e renderização convergem com segurança em uma estação de interface
Dev & Engenharia · Produto & Design

TanStack Router coordena navegações assíncronas sobrepostas

resumo de ~3 min

O problema das navegações sobrepostas

Uma chamada simples a router.navigate() pode envolver várias operações assíncronas simultâneas. Um usuário pode iniciar o pré-carregamento de /account ao passar o cursor sobre o link, clicar nessa rota, mudar para /settings antes da conclusão, encontrar um erro em um carregador e, ao mesmo tempo, disparar um redirecionamento para /login. Para lidar com esse cenário, o TanStack Router separa quatro decisões que antes eram comprimidas em poucas variáveis: qual trabalho de carregamento deve continuar, qual navegação pode publicar seu resultado, o que a tentativa de rota produziu e se o framework realmente renderizou a publicação.

Em uma navegação bem-sucedida, o roteador transforma a URL em uma sequência ordenada de correspondências de rota e cria uma transação corrente, que concede à navegação o direito de publicar enquanto ela continuar sendo a atual. A chamada beforeLoad é executada dos pais para os filhos, em série, porque cada rota filha depende do contexto concluído da anterior. Depois, os carregadores elegíveis podem rodar em paralelo. Se ultrapassarem pendingMs, o roteador pode publicar a interface de espera enquanto a ramificação privada continua sendo processada. Quando os resultados ficam prontos, a navegação publica as correspondências finais, e o framework trata essa publicação.

Trabalho compartilhado e autoridade de publicação

O trabalho de /account pode continuar depois que o usuário muda para /settings porque o pré-carregamento ainda precisa dele. Para impedir execuções duplicadas, o roteador encapsula uma chamada de carregador em um flight, que reúne uma promessa, um controlador de cancelamento e uma contagem de leases. Cada consumidor assume uma concessão própria; a operação só pode ser abortada quando a última concessão é liberada. Assim, perder o direito de publicar não significa que o carregamento deixou de ser útil: seu resultado ainda pode ser armazenado no cache.

A autorização para alterar a página pertence a uma única transação corrente. Quando /settings ocupa esse espaço, /account deixa de poder publicar, mesmo que algum trabalho da rota continue. Em cada fronteira assíncrona, a ramificação privada verifica se ainda corresponde à transação atual; se não corresponder, libera seus recursos, descarta o resultado e encerra sem atualizar a página.

Como os resultados são reduzidos

Cada carregador informa apenas o resultado de sua própria execução. Esses resultados retornam à ramificação privada, que precisa combiná-los antes de decidir o destino da tentativa de rota. Um erro que chega primeiro não determina necessariamente o resultado final, porque carregadores já iniciados ainda podem produzir um redirecionamento. Ao final, a ramificação escolhe entre redirecionar, selecionar uma fronteira de erro ou publicar uma navegação bem-sucedida. O redirecionamento é tratado como fluxo de controle: ele descarta a tentativa de /settings e inicia /login, por isso o erro não chega à interface.

Publicar não é o mesmo que renderizar

A publicação entrega uma nova ramificação ao framework, mas não prova que ela foi confirmada na tela. No React, a árvore pode suspender ou ser substituída antes de o trabalho anterior ser aplicado. Para distinguir esses casos, o roteador mantém um recibo da publicação. Uma nova publicação reconhece o recibo anterior com ack:false; se o framework confirmar a árvore, o adaptador responde ack:true. Apenas a confirmação positiva prova que aquela publicação foi renderizada. O artigo ressalva que “renderizado” significa que o React confirmou a árvore e executou seus efeitos de layout, não necessariamente que o navegador já a exibiu.

A arquitetura mantém separadas as vidas úteis da transação, da ramificação privada, do carregamento compartilhado e do recibo de renderização. Essa separação explica como o roteador pode preservar trabalho útil, impedir publicações obsoletas, priorizar redirecionamentos e aguardar a confirmação efetiva do framework, mantendo uma única promessa pública para navigate().