Um instantâneo de sessão para a aba, não um por instância de gancho

Performancekamo-internal
Navios
26 de agosto de 2026 às 05:40 UTC
Autor
kamo
Enviar
2241a5c

useUserInfo realizou sua sessão em três células useState. Tem 187 locais de chamadas e aproximadamente 27 de eles são montados para toda a sessão — o navegador, cada provedor de shell, o launchpad. A PEDIDO já estava coalescido, então houve apenas uma chamada /api/user-info, mas quando resolveu todas as 27 instâncias chamadas de seu próprio setUserInfo com os mesmos dados. Vinte e sete Atualizações independentes de Reagir com estado idêntico, em cada tabulação e a cada cinco minutos Tick. O estado move-se para uma loja de módulos por trás do usoSyncExternalStore, então uma atualização é uma gravação e um passe de renderização em lote. A loja é app/lib/userInfoStore.ts em vez de um módulo local de gancho por uma razão específica: Nada neste acordo pode pegar uma regressão de direitos. Não existe @testing- library, nenhum teste monta um componente, e app/hooks/** não está na lista de inclusão do vitest — um teste colocado ao lado do Gancho passaria por nunca correr. app/lib/** está incluído, então as regras que o produto agora tem 25 testes cobrindo cada caminho de escrita. Três propriedades são suporte de carga e cada uma é fixada por um ensaio: "Carregamento" começa TRUE e é um trinco de mão única. Os guardas de direitos caem para um DENY, não para uma espera, e checkRight abre com `if (!userInfo) return false` — assim, um relatório de loja loading:false antes que os dados cheguem, renderá "sem permissão" para um membro que detém o direito, e dispara os vinte `useEffect(..., [loading])` redireciona os direitos de leitura no primeiro renderização não carregada. Nada cai e nenhum teste falha. Do mesmo modo nunca deve voltar à verdade, ou cada guarda no aplicativo pisca seu estado de carga a cada cinco minutos. As escritas são apenas de navegador por construção. No servidor, um processo serve a cada concorrente request, assim uma variável de módulo que detém os direitos de um membro é uma compartilhada com cada um dos outros a renderização do membro. publicity () recusa- se a escrever sem uma janela e o getServerSnapshot devolve uma constante congelada em vez de ler o instantâneo mutável. Esta constante é também obrigatória: o shell autenticado é renderizado pelo servidor e este gancho é alcançado durante o passe do servidor árvore cliente do layout root, onde React 19 lança em vez de cair para trás, sem limite acima de AuthedChrome para pegá-lo. A fotografia é mantida, nunca reconstruída. loadUserInfoShared retorna um objeto recentemente analisado a cada tempo, que é precisamente por isso que todas as 27 instâncias re-rendered; um getSnapshot que construiu um Não apenas re-render, mas lançar. Cargas úteis equivalentes já não publicam, por isso os consumidores chaveando memos off userInfo identity — SettingsAppPinsContext's nav gate acima de tudo — stop recomputando a cada cinco minutos para uma carga útil que não mudou. Três decisões valem a pena nomear, pois cada uma tinha uma alternativa defensável: A navegação /logout está agora fechada em que há um assinante. O velho éMontedRef guarda sentado acima do interruptor, não em um setState, então ele pulou o redirecionamento também — uma instância que foi desmontada no meio do voo não navegou. Eliminar o árbitro, que é o movimento habitual ao adoptar um module store, teria silenciosamente promovido esse redirecionamento de condicional para incondicional. Somente a primeira carga é o primeiro plano; as montagens posteriores atualizam-se em segundo plano. Direitos permanecem frescos na navegação como antes, mas um erro transitório em uma montagem tardia não pode mais em branco userInfo for todos os 27 consumidores, quando anteriormente apenas em branco a única instância que o atingiu. As sete chamadas externasUserInfoShared não publicam deliberadamente. Eles disparam sobre websocket reconectar em tempos arbitrários, e conduzir o produto a partir de uma superfície de gatilho ninguém está assistindo é pior do que o impasse limitado de não fazer isso — eles lêem escalar identidade que não pode mudar dentro de uma sessão. Os acessórios são deixados como setas simples de propósito. Estabilizá-los é o instinto natural aqui e quebraria silenciosamente nove locais de chamada — useHrOverview, useAsscrictionPermissions, PlataformaDireitosContexto e outros seis — que dependem da identidade instável de hoje para se manter fresco, calculando uma vez contra um instantâneo nulo. A entrada /logout allowlist no check-client-navigation. mjs segue a linha para a qual existe. Verificado: tsc limpo, todos os 10 guardas passe, 3286 testes verde, compilação de produção, eo servidor standalone ainda renderiza o shell autenticado — 200, 16.238 bytes do DOM em 153 elementos, dois cabeçalhos, dez botões, Minhas Empresas / Meu Perfil / Sair. Quer que um humano clique através do nav de direitos expirados, um membro de direitos limitados, e uma sessão expirando antes dele navios.

Todas as alterações

Como o que vês no transporte?

Cada uma dessas atualizações pousa automaticamente em seu espaço de trabalho. Comece grátis e veja crescer semana após semana.

Começar Livre Para SempreVer Preços