Gerenciando Rotas com React Router
Sep 5, 2016 00:00 · 1036 words · 5 minute read
by Vinicius Dacal
Quando começamos a desenvolver um SPA, uma das primeiras coisas que precisamos definir é a forma como controlamos as rotas da aplicação. Em React isso não é diferente.
React Router é uma lib completa para controle de rotas. Ela permite que você consiga configurar rotas utilizando o formato JSX e também disponibiliza uma API para você configurar diretamente via Javascript.
A lib trabalha com History API, mas também deixa a possibilidade de você trabalhar com Hash(#) se for necessário.
Ela possui features como: Rotas aninhadas, lazy loading de componentes, matching para rotas dinâmicas e controle de transição de rotas, além de possuir suporte a server-rendering.
Para utilizá-la, basta instalar utilizando o npm:
npm install react-router --save
Em nosso exemplo abaixo, podemos ver como ficaria a estrutura básica para uma aplicação de agenda de contatos. Essa aplicação possuirá duas telas: uma tela para a listagem dos contatos e outra tela para a visualização detalhada do contato.
Teremos quatro componentes:
App — O componente container da nossa aplicação.
ContactList — Nossa lista de contatos.
ContactDetail — Nosso componente de visualização de detalhes do contato.
NotFound — Nossa página 404.
No exemplo acima, os componentes estão no mesmo arquivo apenas para fins didáticos. É uma boa prática manter apenas uma definição de componente por arquivo.
No bloco abaixo, temos a definição de todas as nossas rotas. Os componentes que utilizamos para essa definição são o Router e o Route.
Router
Componente raiz da aplicação. Todas as rotas devem ser definidas dentro dele e deve existir somente um Router por aplicação.
O router espera receber o parâmetro history, que é o objeto que ele utilizará para o controle da transição das páginas. Esse objeto é diretamente importado do react-router, podendo ser o browserHistory ou o hashHistory.
Route
É cada rota da nossa aplicação. Espera como parâmetros as props:
path — utiliza para fazer matching com a url.
component — componente que será renderizado caso a url dê matching com o path.
O path aceita alguns formatos para definição da rota:
// Rota estática, ou fixa:
path='contacts'
// Rota com parâmetros:
path='contacts/:id'
// Rota com parâmetros opcionais:
path='contacts(/:id)'
Os parâmetro passados pelas rotas chegam no componente através da propriedade params. No exemplo acima, poderíamos acessar o parâmetro id de dentro do componente respectivo à rota da seguinte forma:
componentDidMount() {
const id = this.props.params.id;
...
}
Outro formato aceito é utilizando o ***, **que funciona como um coringa:
**path=’*’**
fará matching com todas as rotas
**path='contacts/*'**
fará matching com todas as rotas a partir de contacts.
ex:
contacts/
contacts/example
contacts/123
Mais detalhes sobre os formatos suportados podem ser encontrados nesse link da docs.
Um ponto importante a ressaltar é que somente uma rota fará matching por vez, e a prioridade delas vem de cima para baixo. Por esse motivo, conseguimos fazer nossa página 404 apenas utilizando o path=’*’ e colocando ele abaixo de todas as rotas. Caso não for feito matching com nenhuma rota anterior, ele chega nessa rota e renderiza o component NotFound.
Rotas aninhadas
É comum em nossas aplicações utilizarmos rotas aninhadas. No nosso exemplo acima já estamos utilizando, mas talvez não tenha ficado evidente:
<Route path='**/**' component={App}>
<Route path='**contacts**' component={ContactList} />
...
</Route>
Nesse trecho, podemos observar que a rota contacts está aninhada a rota / que é nossa rota raiz.
Nossa rota raiz renderiza o componente App, que atualmente funciona apenas como um layout base da nossa aplicação.
Nele poderíamos colocar o rodapé, o menu e componentes que sempre estarão na tela, independentemente da rota em que estivermos.
Na imagem acima, na linha 7, acessamos a propriedade children que é inserida pelo react router no nosso componente. Nesse caso, children seria o componente respectivo a uma rota aninhada. Por exemplo:
// URL atual: 'http://app.myapp.com/**contacts**'
<Route path='**/**' component={App}>
<Route path='**contacts**' component={**ContactList**} />
<Route path='contacts/:id' component={ContactDetail} />
</Route>
Dada a url atual e a nossa configuração de rotas, o children do nosso componente App seria o componente ContactList.
Abaixo segue um layout que com frequência vemos em aplicações:
No layout acima, temos o menu superior e a sidebar que estarão em todas as telas e temos o conteúdo central, que mudará de uma rota para outra.
Nesse caso, poderíamos manter o Menu e a Sidebar no nosso componente App, renderizando o children ao centro.
render () {
return (
<div>
<Menu />
<Sidebar />
<section className='content-wrapper'>
{children}
</section>
</div>
);
}
Em nosso exemplo da agenda, só utilizamos um nível de aninhamento de rota, mas é possível utilizar quantos forem necessários:
<Route path='/' component={App}>
<Route path='contacts' component={ContactList} />
<Route path='contacts:id' component={**ContactDetail**}>
<Route path='**calls**' component={**ContactCalls**} />
</Route>
</Route>
Nesse exemplo acima, temos uma rota aninhada dentro da visualização do contato. Nessa rota iríamos mostrar, abaixo das informações do contato, uma lista de ligações feitas para o mesmo.
Quando a rota calls fizer matching, o componente ContactCalls estará disponível através da propriedade children do componente ContactDetail.
ContactCall fica como o children de ContactDetail que por sua vez é children de App.
Cat inception
Link
O componente Link é utilizado para fazer a navegação das páginas. esse componente aceita os seguintes parâmetros:
to
O destino para o link, que pode ser passado em dois formatos, string ou objeto.
Em caso de string, deve ser o caminho absoluto para a página, ex:
<Link to='**/contacts/123**'>Contato 123</Link>
Em caso de objeto, pode conter os seguintes parâmetros:
{
**pathname**: 'String representando o caminho para o link',
**query**: 'Um objeto com chave valor dos parâmetros da url',
**hash**: 'Uma hash para colocar na URL, ex: #uma-hash.',
**state**: 'state a ser persistido para o location'
}
activeClassName
className a ser inserido no link quando a url do link em questão estiver ativa. É uma forma fácil de estilizar seu link ativo no menu de navegação.
activeStyle
Bem parecido com o activeClassName, mas ao invés do className, aceita um objeto de estilos CSS.
Os demais atributos podem ser encontrado nesse link da docs.
Com esses componentes, já é possível construir uma aplicação baseada em rotas. Mas o controle de rotas não para apenas por aqui, há outras questões como rotas dinâmicas e controle de autenticação de usuário que eu pretendo abordar em posts futuros.
Para se aprofundar no tema, aconselho começar pela documentação que hoje se encontra no Github.