Descobri que as pessoas podem se intimidar combinando diferentes navegadores no React Navigation para obter padrões de navegação mais "complexos". Hoje, quero guiá-lo brevemente por uma configuração de navegação mais complexa. Iremos falar de:
O Switch Navigator irá representar nosso status do aplicativo autenticado vs. não autenticado
Stack Navigator para navegação normal da direita para a esquerda em vários locais (telas de autenticação, pilha para cada aba, etc)
No tutorial original, Spencer Carlinão está usando a última versão do React Navigation, tomei a liberdade e atualizei os exemplos e irei utilizar versões fixas das dependências. Iremos usar o expo-cli, do mesmo modo que é recomendado na documentação do React Native.
Instale o expo-cli globalmente:
$ yarn global add expo-cli@3.2.3
Criaremos um novo projeto:
$ expo init ExemploNavegacoesComplexas
Iremos escolher blank na tela seguinte:
Navegue até a sua nova pasta:
$ cd ExemploNavegacoesComplexas
E iremos instalar as dependências necessárias para React Navigation:
react-navigation-drawer: Para podermos criar Drawer Navigator.
react-navigation-stack: Para podermos criar Stack Navigator.
react-navigation-tabs: Para podermos criar Tab Navigator
E agora podemos iniciar nossa aplicação:
$ yarn start
Vale notar que os conceitos explicados nesse artigo, podem ser portados para qualquer biblioteca de navegação.
Pré-requisitos
Antes de começarmos, adicionarei um Example.js para servir como uma tela para todas as nossas rotas (afinal, é apenas uma demonstração). Este componente gera uma cor de fundo aleatória e exibe todas as rotas disponíveis na tela atual:
// Example.jsimportReactfrom'react';import{View,TouchableOpacity,Text}from'react-native';constgetAvailableRoutes=navigation=>{letavailableRoutes=[];if (!navigation)returnavailableRoutes;constparent=navigation.dangerouslyGetParent();if (parent){if (parent.router&&parent.router.childRouters){// Grab all the routes the parent defines and add it the listavailableRoutes=[...availableRoutes,...Object.keys(parent.router.childRouters),];}// Recursively work up the tree until there are none leftavailableRoutes=[...availableRoutes,...getAvailableRoutes(parent)];}// De-dupe the list and then remove the current route from the listreturn[...newSet(availableRoutes)].filter(route=>route!==navigation.state.routeName);};constgetRandomColor=()=>{varletters='0123456789ABCDEF';varcolor='#';for (vari=0;i<6;i++){color+=letters[Math.floor(Math.random()*16)];}returncolor;};constExample=({navigation})=>{return (<Viewstyle={{flex:1,alignItems:'center',justifyContent:'center',backgroundColor:getRandomColor(),}}>{getAvailableRoutes(navigation).map(route=>(<TouchableOpacityonPress={()=>navigation.navigate(route)}key={route}style={{backgroundColor:'#fff',padding:10,margin:10,}}><Text>{route}</Text></TouchableOpacity>))}</View>);};exportdefaultExample;
Com isso feito, vamos começar.
Switch Navigator
Para alternar entre os diferentes "estados" da jornada de um usuário, usaremos um navegador switch para que o usuário não possa voltar atrás. Obviamente, teremos uma tela para a jornada principal do aplicativo. Também teremos um para usuários não autenticados.
Além disso, gosto de adicionar uma espécie de tela de Loading. Normalmente, isso não exibe nada - ela serve apenas para determinar se um usuário está autenticado ou não e encaminhá-lo para o lugar certo.
Se um usuário não estiver autenticado, configuraremos um Stack Navigator para que ele saia de uma tela de início, entre, crie uma conta, esqueça a senha ou redefina a senha. As opções típicas que você vê quando precisa se autenticar.
Quando o usuário estiver no aplicativo, usaremos guias para permitir que ele acesse os principais recursos do aplicativo - um feed, pesquisa e uma página de descobertas. Em seguida, substituiremos o item App em nosso navegador App pelo resultado da criação de nossas guias.
A saída da criação de qualquer navegador é apenas um componente para que possamos aninhá-los infinitamente no React Navigation.
Assim como aninhamos o MainTabs em nosso navegador App, permitiremos que cada guia em nosso aplicativo tenha seu próprio stack navigator. Fazendo isso, significa que cada guia terá seu próprio estado, para que o usuário possa ir para a tela de detalhes de uma guia, mudar para outra e, ao voltar, poderá manter o mesmo estado para cada guia.
Além disso, com este exemplo, você pode ver que os navegadores obterão o nome da rota correspondente mais próxima. Isso significa que podemos reutilizar os nomes de tela e cada pilha apenas captura a tela Details mais próxima disponível, na pilha ou acima dela, na hierarquia do navegador.
Faremos o mesmo com o Drawer Navigator. Criaremos o navegador (também criaremos uma pilha para tela de configurações, dando um motivo criarmos o drawer) e renderizaremos isso como uma tela.
Desta vez, vamos substituir a renderização de MainTabs com MainDrawer e tornaremos nossas guias dentro do drawer. Construir essa hierarquia significa que estamos apenas adicionando mais navegadores, mas tudo o que já estava lá continuará funcionando.
Finalmente, queremos adicionar um navegador que se mova de baixo para cima e cubra qualquer outra tela. Isso significa que ele precisa estar na posição mais alta da nossa pilha (raiz/root). Se estiver na raiz, estará disponível para ser renderizado a partir de qualquer um de seus filhos.
Você pode encontrar o código final nesse repositório no GitHub. Aproveitei e separei cada exemplo em um commit separado, para você poder ver o que mudou em cada etapa.