Roteamento universal para aplicativos de reação

Se você tentar descrever brevemente em que consiste a função de roteamento no front-end de aplicativos da Web, poderá concluir que cada estrutura popular tem uma idéia completamente diferente disso. Mesmo comparando as versões da mesma estrutura, podemos concluir que as funções e APIs de roteamento são mais suscetíveis a alterações (geralmente sem compatibilidade com versões anteriores). Por exemplo, a quarta versão do roteamento no React foi redesenhada de forma tão radical que alguns projetos populares no githab.com não mudaram para esta versão.

Por trás de tudo isso, há uma tendência geral, que, na minha opinião, é que a funcionalidade de roteamento em muitas estruturas populares de front-end está sobrecarregada. Nesse sentido, ele se torna fortemente conectado a outros componentes que podem ser isolados do roteamento (por exemplo, navegação, histórico, links etc.). Portanto, provavelmente, muitos estão familiarizados com a sensação de que o uso do roteamento se torna desconfortável e sua expansão é simplesmente impossível. Comparado aos componentes flexíveis e extensíveis, o roteamento em estruturas populares de front-end parece muito menos conveniente e não é expansível. Isso é especialmente verdade nas primeiras versões (até a quarta) do roteamento no React.

Neste post, examinarei alguns pontos históricos que levaram a esse estado de coisas com roteamento, bem como o uso da biblioteca de roteador universal, junto com o React.

O roteamento é necessário?


Tecnicamente, um aplicativo Web de uma página pode funcionar sem roteamento. Por exemplo, como não há roteamento no aplicativo de desktop. Tudo funcionaria quase bem se o aplicativo da web de uma página não permanecesse o mesmo aplicativo de navegador da web. Ou seja, o usuário pode atualizar a página a qualquer momento pressionando a tecla F5 ou clicando no ícone "Recarregar" do navegador. Ou o usuário pode rolar a história para frente ou para trás a qualquer momento, clicando nos ícones "Seta para a esquerda" e "Seta para a direita" ou pressionando a tecla "Backspace".

Portanto, para um aplicativo de página única, uma alteração de componentes e um estado interno do aplicativo sempre devem ser acompanhados por uma alteração no URL.

Por que o roteamento é tão?


A função de roteamento em estruturas populares para aplicativos Web front-end, na minha opinião, é afetada por sua conexão histórica com o roteamento em aplicativos Web clássicos (com renderização do servidor).

Inicialmente, url era o endereço da Web de um documento estático da Web e era muito simples. Em seguida, começou a adaptação da arquitetura MVC à Web: Modelo 1 e Modelo 2. O último deles inclui um controlador frontal, que posteriormente foi dividido em duas partes: roteamento (que seleciona o controlador desejado) e o próprio controlador, que trabalha com o modelo e renderizar vista. Como você pode ver, em um aplicativo Web clássico, o roteamento determina a ação (controlador) e, indiretamente (por meio do controlador), determina a visualização que deve ser renderizada no servidor.

Ou seja, a arquitetura da área de trabalho foi adaptada ao mesmo tempo para trabalhar com o aplicativo Web clássico no servidor e, em seguida, retornou à frente do aplicativo Web na forma de roteamento, sobrecarregado com as funções necessárias no lado do servidor.

O que a biblioteca de roteador universal oferece?


A biblioteca de roteador universal oferece descartar tudo o que é supérfluo e deixar apenas a parte que pode ser usada com ou sem estrutura ao renderizar no cliente e no lado do servidor da web (em aplicativos da web universais / isomórficos).

Tendo rejeitado todos os estratos do tempo, o roteador universal oferece apenas uma função claramente definida. Com base na linha (enfatizo a linha novamente e não o objeto de histórico, local etc.), chame a função assíncrona, que passará a string de URL analisada como os parâmetros reais. Isso é tudo. Como pode parecer no React:

import React from 'react'; import UniversalRouter from 'universal-router'; import App from './App'; import Link from './Link'; const routes = { path: '/', async action({next}) { const children = await next(); return ( <App> {children} </App> ); }, children: [ { path: '', async action() { return ( <div>Root route go to <Link href='/test'>Test</Link></div> ); }, }, { path: '/test', async action({next}) { const children = await next(); return ( <App> {children} </App> ); }, children: [ { path: '', async action() { return ( <div>Test route return to <Link href='/'>Root</Link></div> ); }, }, ] }, ], }; export const basename = ''; const router = new UniversalRouter(routes, { baseUrl: basename }); export default router; 

Rotas aninhadas também são suportadas. Eles são definidos no campo filho e você pode obtê-los chamando a próxima função assíncrona ().

E como isso funciona com o React?


Defina o método navigate () para o histórico, embora em muitos casos seja suficiente usar o método push () nativo

 import { createBrowserHistory } from 'history' import parse from 'url-parse' import deepEqual from 'deep-equal' const isNode = new Function('try {return this===global;}catch(e){return false;}') //eslint-disable-line let history if (!isNode()) { history = createBrowserHistory() history.navigate = function (path, state) { const parsedPath = parse(path) const location = history.location if (parsedPath.pathname === location.pathname && parsedPath.query === location.search && parsedPath.hash === location.hash && deepEqual(state, location.state)) { return } const args = Array.from(arguments) args.splice(0, 2) return history.push(...[path, state, ...args]) } } else { history = {} history.navigate = function () {} } export default history 

Também criamos o componente Link que acionará a navegação:

 import React from 'react'; import {basename} from './router'; import history from './history'; function noOp(){}; const createOnClickAnchor = (callback) => { return (e) => { e.preventDefault(); history.navigate(e.currentTarget.getAttribute('href')); callback(e); }; }; export default ({href, onClick = noOp, children, ...rest}) => ( <a href={basename + href} onClick={createOnClickAnchor(onClick)} {...rest} > {children} </a> ); 

Agora você está pronto para renderizar o componente:

 import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; import history from './history'; import router from './router'; const render = async (location) => { const element = await router.resolve(location); ReactDOM.render( element, document.getElementById('root'), ); }; render(history.location); history.listen(render); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister(); 

Código do projeto

Links úteis

1. medium.com/@ippei.tanaka/universal-router-history-react-97ec79464573

Source: https://habr.com/ru/post/pt484514/


All Articles