Atividade 25: O Mini Portfólio (Rotas Manuais)
A Consagração do App! Crie Múltiplas Visões (Telas) Trocando
componentes como Cartas com o poder supremo do useState e o Renders Condicionais.
🎯 O que vamos construir
-
✓
Multi-Telas Sem Lib (React Navigation/Router):
const [tela, setTela] = useState('Home') -
✓
Extrair Códigos JS para Funcões Renrerizadoras (
function TelaHome() { return <View/>... }) - ✓ Menu Bottom Navigation Falso de Alta Performance feito com Flexbox
🧭 Navegação Falsa Baseada em Componentes
A maior Dúvida dos Desenvolvedores Web ao chegar no Mobile: "Como eu abro outra página se não existe o <a href> do HTML"?. Enquanto usamos Bibliotecas complexas reais para Aplicativos enormes Empresariais, nós podemos criar Aplicativos Menores Múltiplos com abas de forma MANUAL em 2 minutos!
A Tática do Switch e do If
Se dividirmos nosso código em blocos de Componentes Independentes, nós podemos pedir pro React Renderizar na Tela só o bloco Específico que casa com a variável de estado que tá Ativa! Os outros blocos (outras telas) ficam mortos no limbo de RAM economizando processador.
const [telaAtual, setTelaAtual] = useState('HOME');
// E no seu Render principal do App.js:
return (
<View>
{ telaAtual === 'HOME' && <ComponenteDeHome /> }
{ telaAtual === 'SOBRE_MIM' && <ComponenteSobre /> }
{ telaAtual === 'PROJETOS' && <ComponenteProjetos /> }
</View>
);
💻 O Super Portal Tab-Bar
Abra o Expo Snack. Vamos codar a estrutura inteira de Abas Inferiores flutuantes que mudam de cor conforme a Rota selecionada e alteram os Gigantescos Blocos Visuais que rodam no meio!
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, ScrollView, StyleSheet } from 'react-native';
export default function App() {
// 1) O Roteador Central (Router Root State)
const [telaAtiva, setTelaAtiva] = useState('HOME');
// ==============================================
// 2) MINI COMPONENTES DE TELA
// ==============================================
const TelaHome = () => (
<View style={styles.telaRender}>
<Text style={styles.tituloSecao}>🏠 Bem Vindo!</Text>
<Text style={styles.textoCorpo}>Este é o meu Mini Portfólio construído em React Native puro, sem depender de pesados Routers Externos. A mágica é toda baseada em Troca de Componentes visuais! Navegue nos botões abaixo para ver minha experiência.</Text>
</View>
)
const TelaSkill = () => (
<View style={styles.telaRender}>
<Text style={styles.tituloSecao}>⚙️ Habilidades</Text>
<View style={styles.pillsContainer}>
<Text style={styles.pill}>React Native</Text>
<Text style={styles.pill}>Javascript</Text>
<Text style={styles.pill}>Tailwind CSS</Text>
<Text style={styles.pill}>PHP Backend</Text>
<Text style={styles.pill}>MySQL Server</Text>
</View>
</View>
)
const TelaCases = () => (
<View style={styles.telaRender}>
<Text style={styles.tituloSecao}>🚀 Meus Projetos</Text>
<View style={styles.cardCase}>
<Text style={styles.caseName}>App de Tarefas V2</Text>
<Text style={styles.textoCorpo}>To-Do List profissional com Arrays Invertidas e Filtros Inteligentes de Checkboxes.</Text>
</View>
<View style={styles.cardCase}>
<Text style={styles.caseName}>Calculadora de Neon</Text>
<Text style={styles.textoCorpo}>Flexbox UI Calculator que utiliza Parseamento Matemático de Expressões no Native C++.</Text>
</View>
</View>
)
// ==============================================
// 3) RENDERIZAÇÃO MESTRE DA PÁGINA FIXA (MOLDURA)
// ==============================================
return (
<View style={styles.container}>
<View style={styles.headerMestre}>
<Text style={styles.logoText}>MeuPortfolio.APP</Text>
</View>
{/* AREA DO MEIO: CHROMA SCREEN QUE MUDA DINAMICAMENTE */}
<ScrollView style={styles.areaConteudo}>
{ telaAtiva === 'HOME' && <TelaHome /> }
{ telaAtiva === 'SKILLS' && <TelaSkill /> }
{ telaAtiva === 'CASES' && <TelaCases /> }
</ScrollView>
{/* O BOTTOM TAB BAR FIXO LÁ EMBAIXO! */}
<View style={styles.tabBar}>
<TouchableOpacity
style={[styles.tabBtn, telaAtiva === 'HOME' && styles.tabAtiva]}
onPress={() => setTelaAtiva('HOME')}
>
<Text style={[styles.tabTxt, telaAtiva === 'HOME' && styles.tabTxtAtivo]}>Início</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.tabBtn, telaAtiva === 'SKILLS' && styles.tabAtiva]}
onPress={() => setTelaAtiva('SKILLS')}
>
<Text style={[styles.tabTxt, telaAtiva === 'SKILLS' && styles.tabTxtAtivo]}>Skills</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.tabBtn, telaAtiva === 'CASES' && styles.tabAtiva]}
onPress={() => setTelaAtiva('CASES')}
>
<Text style={[styles.tabTxt, telaAtiva === 'CASES' && styles.tabTxtAtivo]}>Projetos</Text>
</TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#fdf4ff' },
headerMestre: { paddingTop: 60, paddingBottom: 20, backgroundColor: '#1e1b4b', alignItems: 'center' },
logoText: { color: 'white', fontWeight: '900', fontSize: 18, letterSpacing: 2 },
areaConteudo: { flex: 1, padding: 25 },
telaRender: { paddingBottom: 50 }, // Margem pra conseguir scrollar por causa do tab
tituloSecao: { fontSize: 28, fontWeight: 'bold', color: '#312e81', marginBottom: 20 },
textoCorpo: { fontSize: 16, color: '#4f46e5', lineHeight: 24 },
pillsContainer: { flexDirection: 'row', flexWrap: 'wrap', gap: 10 },
pill: { backgroundColor: '#818cf8', color: 'white', paddingHorizontal: 15, paddingVertical: 8, borderRadius: 20, fontWeight: 'bold' },
cardCase: { backgroundColor: 'white', padding: 20, borderRadius: 15, marginBottom: 15, elevation: 4, shadowColor: '#4f46e5', shadowOpacity: 0.1 },
caseName: { fontSize: 18, fontWeight: 'bold', color: '#312e81', borderBottomWidth: 1, borderColor: '#e0e7ff', paddingBottom: 10, marginBottom: 10 },
tabBar: { flexDirection: 'row', backgroundColor: 'white', padding: 15, paddingBottom: 30, borderTopColor: '#e0e7ff', borderTopWidth: 1, elevation: 20 },
tabBtn: { flex: 1, alignItems: 'center', paddingVertical: 10 },
tabTxt: { color: '#a5b4fc', fontWeight: 'bold', fontSize: 14 },
tabAtiva: { backgroundColor: '#eef2ff', borderRadius: 10 },
tabTxtAtivo: { color: '#4f46e5' }
});