Saltar para o conteúdo
React Native com Expo: Do Zero ao Primeiro App
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 start

Escaneie 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 app

Componentes 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:ios

Pró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.