Mobile
React Native com Expo: Do Zero ao Primeiro App
10 de maio de 2026·Paulo Pereira
Por que React Native + Expo?
React Native permite criar apps iOS e Android com JavaScript/TypeScript. Expo adiciona uma camada que elimina a necessidade de configurar Xcode e Android Studio para a maioria dos casos — você começa a rodar no celular em 5 minutos.
Setup
npx create-expo-app meu-app --template blank-typescript
cd meu-app
npx expo startEscaneie o QR code com o app Expo Go no celular. Qualquer mudança no código atualiza o app instantaneamente.
Estrutura de Arquivos
meu-app/
├── app/ # Expo Router (file-based routing)
│ ├── _layout.tsx # Layout raiz
│ ├── index.tsx # Tela inicial (/)
│ └── perfil.tsx # Tela /perfil
├── components/ # Componentes reutilizáveis
├── assets/ # Imagens, fontes
└── app.json # Configuração do appComponentes Básicos
// app/index.tsx
import { StyleSheet, Text, View, TouchableOpacity, ScrollView } from 'react-native';
import { StatusBar } from 'expo-status-bar';
export default function HomeScreen() {
return (
<ScrollView contentContainerStyle={styles.container}>
<StatusBar style="dark" />
<Text style={styles.titulo}>Meu App</Text>
<Text style={styles.subtitulo}>Feito com React Native + Expo</Text>
<TouchableOpacity
style={styles.botao}
onPress={() => alert('Olá!')}
activeOpacity={0.8}
>
<Text style={styles.botaoTexto}>Toque aqui</Text>
</TouchableOpacity>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 24,
backgroundColor: '#fff',
},
titulo: {
fontSize: 32,
fontWeight: 'bold',
color: '#1a1a2e',
marginBottom: 8,
},
subtitulo: {
fontSize: 16,
color: '#6b7280',
marginBottom: 32,
textAlign: 'center',
},
botao: {
backgroundColor: '#3B82F6',
paddingVertical: 14,
paddingHorizontal: 32,
borderRadius: 12,
},
botaoTexto: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});FlatList: Listas Performáticas
import { FlatList, Text, View, StyleSheet } from 'react-native';
type Item = { id: string; titulo: string; descricao: string };
const dados: Item[] = [
{ id: '1', titulo: 'React Native', descricao: 'Framework mobile' },
{ id: '2', titulo: 'Expo', descricao: 'Plataforma de desenvolvimento' },
{ id: '3', titulo: 'TypeScript', descricao: 'JavaScript tipado' },
];
function CartaoItem({ item }: { item: Item }) {
return (
<View style={styles.cartao}>
<Text style={styles.titulo}>{item.titulo}</Text>
<Text style={styles.desc}>{item.descricao}</Text>
</View>
);
}
export default function ListaScreen() {
return (
<FlatList
data={dados}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <CartaoItem item={item} />}
contentContainerStyle={{ padding: 16, gap: 12 }}
/>
);
}Navegação com Expo Router
Expo Router usa a estrutura de arquivos para definir rotas — igual ao Next.js:
// app/_layout.tsx
import { Stack } from 'expo-router';
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" options={{ title: 'Início' }} />
<Stack.Screen name="perfil" options={{ title: 'Meu Perfil' }} />
</Stack>
);
}// Navegação entre telas
import { Link, useRouter } from 'expo-router';
// Via componente Link
<Link href="/perfil">
<Text>Ver perfil</Text>
</Link>
// Via programático
const router = useRouter();
router.push('/perfil');
router.push({ pathname: '/artigo/[id]', params: { id: '123' } });Buscando Dados com useEffect
import { useState, useEffect } from 'react';
import { ActivityIndicator, FlatList, Text } from 'react-native';
type Post = { id: number; title: string; body: string };
export default function PostsScreen() {
const [posts, setPosts] = useState<Post[]>([]);
const [carregando, setCarregando] = useState(true);
const [erro, setErro] = useState<string | null>(null);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
.then(r => r.json())
.then(dados => setPosts(dados))
.catch(() => setErro('Erro ao carregar posts'))
.finally(() => setCarregando(false));
}, []);
if (carregando) return <ActivityIndicator style={{ flex: 1 }} />;
if (erro) return <Text>{erro}</Text>;
return (
<FlatList
data={posts}
keyExtractor={(p) => String(p.id)}
renderItem={({ item }) => <Text>{item.title}</Text>}
/>
);
}Testando no Celular
# Instale Expo Go no celular (iOS App Store / Google Play)
npx expo start
# Para Android via USB (mais rápido)
npx expo start --android
# Build de produção (sem Expo Go)
npx expo build:android
npx expo build:iosPróximos Passos
Após dominar os fundamentos:
- State management: Zustand ou Context API
- Forms: React Hook Form + Zod
- Animações: Reanimated 3
- Build e deploy: EAS Build + EAS Submit
Conclusão
React Native com Expo é o caminho mais rápido para ter um app mobile funcionando. O ecossistema amadureceu muito nos últimos anos — hoje é uma escolha sólida tanto para protótipos quanto para apps em produção.