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)
- Stack Navigator para navegação de baixo para cima
- Tab Navigator
- Drawer Navigator
Antes de começar
No tutorial original, Spencer Carli nã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:
$ expo install react-navigation@4.0.10 react-native-gesture-handler@1.3.0 react-native-reanimated@1.2.0
Agora, iremos adicionar os pacotes de navegadores do React Navigation:
$ expo install react-navigation-tabs@2.5.5 react-navigation-stack@1.9.3 react-navigation-drawer@2.2.2
- 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.js
import React from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
const getAvailableRoutes = navigation => {
let availableRoutes = [];
if (!navigation) return availableRoutes;
const parent = navigation.dangerouslyGetParent();
if (parent) {
if (parent.router && parent.router.childRouters) {
// Grab all the routes the parent defines and add it the list
availableRoutes = [
...availableRoutes,
...Object.keys(parent.router.childRouters),
];
}
// Recursively work up the tree until there are none left
availableRoutes = [...availableRoutes, ...getAvailableRoutes(parent)];
}
// De-dupe the list and then remove the current route from the list
return [...new Set(availableRoutes)].filter(
route => route !== navigation.state.routeName
);
};
const getRandomColor = () => {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};
const Example = ({ navigation }) => {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: getRandomColor(),
}}
>
{getAvailableRoutes(navigation).map(route => (
<TouchableOpacity
onPress={() => navigation.navigate(route)}
key={route}
style={{
backgroundColor: '#fff',
padding: 10,
margin: 10,
}}
>
<Text>{route}</Text>
</TouchableOpacity>
))}
</View>
);
};
export default Example;
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.
// App.js
import React from 'react';
import {
createAppContainer,
createSwitchNavigator,
} from 'react-navigation';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import { createDrawerNavigator } from 'react-navigation-drawer';
import { createStackNavigator } from 'react-navigation-stack';
import Example from './Example';
const App = createSwitchNavigator({
Loading: {
screen: Example,
},
Auth: {
screen: Example,
},
App: {
screen: Example,
},
});
export default createAppContainer(App);
Stack Navigator de autenticação
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.
// App.js
// ...
const AuthStack = createStackNavigator({
Landing: {
screen: Example,
navigationOptions: {
headerTitle: 'Landing',
},
},
SignIn: {
screen: Example,
navigationOptions: {
headerTitle: 'Sign In',
},
},
CreateAccount: {
screen: Example,
navigationOptions: {
headerTitle: 'Create Account',
},
},
ForgotPassword: {
screen: Example,
navigationOptions: {
headerTitle: 'Forgot Password',
},
},
ResetPassword: {
screen: Example,
navigationOptions: {
headerTitle: 'Reset Password',
},
},
});
const App = createSwitchNavigator({
Loading: {
screen: Example,
},
Auth: {
screen: AuthStack,
},
App: {
screen: Example,
},
});
export default createAppContainer(App);
App Tabs
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.
// App.js
// ...
const MainTabs = createBottomTabNavigator({
Feed: {
screen: Example,
navigationOptions: {
tabBarLabel: 'Feed',
},
},
Search: {
screen: Example,
navigationOptions: {
tabBarLabel: 'Search',
},
},
Discover: {
screen: Example,
navigationOptions: {
tabBarLabel: 'Discover',
},
},
});
const App = createSwitchNavigator({
Loading: {
screen: Example,
},
Auth: {
screen: AuthStack,
},
App: {
screen: MainTabs,
},
});
// ...
Stack Navigator para cada guia do App Tab
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.
// App.js
// ...
const FeedStack = createStackNavigator({
Feed: {
screen: Example,
navigationOptions: {
headerTitle: 'Feed',
},
},
Details: {
screen: Example,
navigationOptions: {
headerTitle: 'Details',
},
},
});
const SearchStack = createStackNavigator({
Search: {
screen: Example,
navigationOptions: {
headerTitle: 'Search',
},
},
Details: {
screen: Example,
navigationOptions: {
headerTitle: 'Details',
},
},
});
const DiscoverStack = createStackNavigator({
Discover: {
screen: Example,
navigationOptions: {
headerTitle: 'Discover',
},
},
Details: {
screen: Example,
navigationOptions: {
headerTitle: 'Details',
},
},
});
const MainTabs = createBottomTabNavigator({
Feed: {
screen: FeedStack,
navigationOptions: {
tabBarLabel: 'Feed',
},
},
Search: {
screen: SearchStack,
navigationOptions: {
tabBarLabel: 'Search',
},
},
Discover: {
screen: DiscoverStack,
navigationOptions: {
tabBarLabel: 'Discover',
},
},
});
// ...
App Drawer
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.
// App.js
// ...
const SettingsStack = createStackNavigator({
SettingsList: {
screen: Example,
navigationOptions: {
headerTitle: 'Settings List',
},
},
Profile: {
screen: Example,
navigationOptions: {
headerTitle: 'Profile',
},
},
});
const MainDrawer = createDrawerNavigator({
MainTabs: MainTabs,
Settings: SettingsStack,
});
const App = createSwitchNavigator({
Loading: {
screen: Example,
},
Auth: {
screen: AuthStack,
},
App: {
screen: MainDrawer,
},
});
// ...
Stack Navigator no estilo modal
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.
// App.js
// ...
const AppModalStack = createStackNavigator(
{
App: MainDrawer,
Promotion1: {
screen: Example,
},
},
{
mode: 'modal',
headerMode: 'none',
}
);
const App = createSwitchNavigator({
Loading: {
screen: Example,
},
Auth: {
screen: AuthStack,
},
App: {
screen: AppModalStack,
},
});
export default createAppContainer(App);
Código final do nosso navegador
E para finalizar, aqui está o nosso código ao final desse tutorial:
import React from 'react';
import {
createAppContainer,
createSwitchNavigator,
} from 'react-navigation';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import { createDrawerNavigator } from 'react-navigation-drawer';
import { createStackNavigator } from 'react-navigation-stack';
import Example from './Example';
const AuthStack = createStackNavigator({
Landing: {
screen: Example,
navigationOptions: {
headerTitle: 'Landing',
},
},
SignIn: {
screen: Example,
navigationOptions: {
headerTitle: 'Sign In',
},
},
CreateAccount: {
screen: Example,
navigationOptions: {
headerTitle: 'Create Account',
},
},
ForgotPassword: {
screen: Example,
navigationOptions: {
headerTitle: 'Forgot Password',
},
},
ResetPassword: {
screen: Example,
navigationOptions: {
headerTitle: 'Reset Password',
},
},
});
const FeedStack = createStackNavigator({
Feed: {
screen: Example,
navigationOptions: {
headerTitle: 'Feed',
},
},
Details: {
screen: Example,
navigationOptions: {
headerTitle: 'Details',
},
},
});
const SearchStack = createStackNavigator({
Search: {
screen: Example,
navigationOptions: {
headerTitle: 'Search',
},
},
Details: {
screen: Example,
navigationOptions: {
headerTitle: 'Details',
},
},
});
const DiscoverStack = createStackNavigator({
Discover: {
screen: Example,
navigationOptions: {
headerTitle: 'Discover',
},
},
Details: {
screen: Example,
navigationOptions: {
headerTitle: 'Details',
},
},
});
const MainTabs = createBottomTabNavigator({
Feed: {
screen: FeedStack,
navigationOptions: {
tabBarLabel: 'Feed',
},
},
Search: {
screen: SearchStack,
navigationOptions: {
tabBarLabel: 'Search',
},
},
Discover: {
screen: DiscoverStack,
navigationOptions: {
tabBarLabel: 'Discover',
},
},
});
const SettingsStack = createStackNavigator({
SettingsList: {
screen: Example,
navigationOptions: {
headerTitle: 'Settings List',
},
},
Profile: {
screen: Example,
navigationOptions: {
headerTitle: 'Profile',
},
},
});
const MainDrawer = createDrawerNavigator({
MainTabs: MainTabs,
Settings: SettingsStack,
});
const AppModalStack = createStackNavigator(
{
App: MainDrawer,
Promotion1: {
screen: Example,
},
},
{
mode: 'modal',
headerMode: 'none',
}
);
const App = createSwitchNavigator({
Loading: {
screen: Example,
},
Auth: {
screen: AuthStack,
},
App: {
screen: AppModalStack,
},
});
export default createAppContainer(App);
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.
https://github.com/oieduardorabelo/react-native-complex-navigation-with-react-navigation
oieduardorabelo / react-native-complex-navigation-with-react-navigation
📱React Native example for complex react-navigation setup
NOT MAINTAINED
The example in this repository is 3-4 years old. Things changed in the ecosystem.
Take it with a grain of salt 😄
React Native: Complex navigation with React Navigation
Example project for my articles on:
- Medium: https://medium.com/@oieduardorabelo/react-native-navegações-complexas-com-react-navigation-583a8f5a4a7
- Dev.to: https://dev.to/oieduardorabelo/react-native-navegacoes-complexas-com-react-navigation-2abp
All credits to Complex Navigation Example with React Navigation by Spencer Carli
changelog
- In the original tutorial Spencer Carli, isn't using the last version of React Navigation
- I've updated all examples + locking dependencies version
- And you can find every step in a separated commit in the git history
Créditos
- Complex Navigation Example with React Navigation, escrito originalmente por Spencer Carli
Top comments (0)