O que é React Native?
React Native é um framework open-source criado pelo Facebook (Meta) que permite desenvolver aplicativos móveis para iOS e Android usando apenas JavaScript e React — sem precisar escrever código nativo em Swift ou Kotlin.
Nativo vs. Multiplataforma
Antes do React Native, existiam três abordagens para criar apps. Entender as diferenças é fundamental para justificar a escolha da ferramenta certa para cada projeto.
Nativo Puro
Swift/Kotlin. Máxima performance, acesso total ao hardware. Dois codebases para manter.
React Native
JavaScript que compila para componentes nativos reais. Um codebase, performance próxima ao nativo.
Híbrido/WebView
HTML dentro de um container. Fácil, mas performance visivelmente inferior ao nativo.
<View> e <Text> — não são HTML: eles são mapeados
para UIView no iOS e android.view.View no Android.
Na arquitetura nova (JSI + Fabric), essa comunicação é ainda mais direta e síncrona.
Por que usar o Expo?
O Expo é uma plataforma construída sobre o React Native que abstrai toda a configuração complexa de Xcode e Android Studio. Para aprendizado e para a maioria dos projetos profissionais, o Expo é a escolha certa.
Sem configuração nativa
Não precisa de Mac para testar no iOS. Não precisa configurar Android Studio.
SDK rico
Câmera, GPS, notificações, sensores — tudo com APIs simples e documentação clara.
Hot Reload
Veja as mudanças instantaneamente no app físico ou no simulador, sem recompilar.
Configurando o Ambiente
Para desenvolver com Expo, você precisa de apenas três ferramentas instaladas na sua máquina. O processo leva menos de 10 minutos.
Pré-requisitos
Node.js (versão 18 ou superior)
Baixe em nodejs.org. O Node inclui o npm, que usaremos para instalar pacotes. Confirme a instalação com node --version no terminal.
Visual Studio Code
Editor recomendado. Instale as extensões: React Native Tools (Microsoft) e Prettier para formatação automática.
Expo Go no celular
Baixe o app Expo Go na Play Store (Android) ou App Store (iOS). Com ele, você vai rodar seu app no dispositivo físico sem precisar compilar.
Expo CLI (global)
Com o Node instalado, rode no terminal:
npm install -g expo-cli
# Verifique a instalação
expo --version
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
Verificando tudo
node --version # deve mostrar v18.x.x ou superior
npm --version # deve mostrar 9.x.x ou superior
expo --version # deve mostrar a versão do Expo CLI
Criando o Primeiro Projeto
Com o ambiente configurado, criar um projeto Expo é um único comando. Você terá um app funcional rodando no seu celular em menos de 5 minutos.
Criando o projeto
# Cria um novo projeto com o template em branco
npx create-expo-app meu-primeiro-app --template blank
# Entra na pasta do projeto
cd meu-primeiro-app
# Inicia o servidor de desenvolvimento
npx expo start
Após rodar npx expo start, um QR code aparece no terminal.
Abra o app Expo Go no celular e escaneie o QR code. O app vai carregar no seu dispositivo.
O arquivo App.js inicial
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
// Importa componentes nativos do React Native
// Não existe <div>, <p> ou <span> — tudo é componente nativo
export default function App() {
// Função que retorna JSX — a sintaxe que mistura JS com "HTML nativo"
return (
<View style={styles.container}>
{/* View é equivalente a uma <div> no HTML */}
<Text>Olá, Mundo!</Text>
{/* Text é o único componente que pode conter texto diretamente */}
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1, // Ocupa toda a tela disponível
backgroundColor: '#fff',
alignItems: 'center', // Centraliza horizontalmente
justifyContent: 'center', // Centraliza verticalmente
},
});
<div>, <p>, <span> ou qualquer tag HTML.
No React Native, usamos componentes específicos: <View> no lugar de <div>,
<Text> no lugar de <p>, <Image> para imagens.
Todo texto visível DEVE estar dentro de um componente <Text>.
Estrutura do Projeto
Entender a estrutura de arquivos gerada pelo Expo é o primeiro passo para navegar pelo código com segurança e organizar seus próprios projetos.
├── App.js ← Ponto de entrada da aplicação
├── app.json ← Configurações do app (nome, ícone, versão)
├── package.json ← Dependências e scripts do projeto
├── babel.config.js ← Transpilador (não mexa aqui)
├── assets/ ← Imagens, fontes e ícones
│ ├── icon.png
│ └── splash.png
└── node_modules/ ← Dependências instaladas (nunca edite)
O arquivo app.json
{
"expo": {
"name": "Meu Primeiro App", // Nome exibido embaixo do ícone no celular
"slug": "meu-primeiro-app", // Identificador único na URL do Expo
"version": "1.0.0", // Versão do app (major.minor.patch)
"orientation": "portrait", // portrait | landscape | default
"icon": "./assets/icon.png", // Ícone do app (1024x1024px recomendado)
"splash": {
"image": "./assets/splash.png", // Tela de carregamento
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"platforms": ["ios", "android"] // Plataformas alvo
}
}
Organização recomendada para projetos maiores
├── App.js
├── src/
│ ├── components/ ← Componentes reutilizáveis
│ ├── screens/ ← Telas completas da aplicação
│ ├── hooks/ ← Hooks customizados
│ ├── services/ ← Chamadas de API
│ └── utils/ ← Funções auxiliares
└── assets/
Componentes Essenciais
React Native oferece um conjunto de componentes que correspondem a elementos visuais nativos do iOS e Android. Dominar esses componentes base é o alicerce de todo desenvolvimento.
View e Text
import { View, Text, StyleSheet } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<View style={styles.card}>
{/* View pode ser aninhada: funciona como <div> com Flexbox */}
<Text style={styles.titulo}>React Native</Text>
<Text style={styles.descricao}>
Todo texto DEVE estar dentro de um componente Text.
Não existe texto "solto" fora de Text no React Native.
</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f0f0f0',
padding: 20,
justifyContent: 'center',
},
card: {
backgroundColor: '#fff',
borderRadius: 12,
padding: 20,
// Sombra no iOS
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
// Sombra no Android
elevation: 3,
},
titulo: {
fontSize: 22,
fontWeight: 'bold',
color: '#1a1a1a',
marginBottom: 8,
},
descricao: {
fontSize: 14,
color: '#666',
lineHeight: 22,
},
});
Image
import { View, Image, StyleSheet } from 'react-native';
export default function App() {
return (
<View>
{/* Imagem local (dentro do projeto) */}
<Image
source={require('./assets/icon.png')}
style={styles.imagemLocal}
/>
{/* Imagem remota (URL) — OBRIGATÓRIO informar width e height */}
<Image
source={{ uri: 'https://picsum.photos/300/200' }}
style={styles.imagemRemota}
resizeMode="cover" // cover | contain | stretch | center
/>
</View>
);
}
const styles = StyleSheet.create({
imagemLocal: {
width: 80,
height: 80,
borderRadius: 40, // Torna circular (metade do width/height)
},
imagemRemota: {
width: '100%', // 100% da largura do pai
height: 200,
borderRadius: 12,
},
});
TouchableOpacity e Pressable
import { View, Text, TouchableOpacity, Pressable, StyleSheet } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
{/* TouchableOpacity: reduz a opacidade ao pressionar */}
<TouchableOpacity
style={styles.botao}
onPress={() => alert('Botão pressionado!')}
activeOpacity={0.7} // Opacidade ao pressionar (0 a 1)
>
<Text style={styles.textoBotao}>Toque aqui</Text>
</TouchableOpacity>
{/* Pressable: mais moderno, mais controle de estados */}
<Pressable
style={({ pressed }) => [
styles.botao,
pressed && { opacity: 0.6, transform: [{ scale: 0.97 }] }
]}
onPress={() => console.log('Pressable!')}
>
<Text style={styles.textoBotao}>Pressable moderno</Text>
</Pressable>
</View>
);
}
TextInput
import { useState } from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';
export default function App() {
const [nome, setNome] = useState('');
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Digite seu nome"
placeholderTextColor="#999"
value={nome}
onChangeText={setNome} // Chamado a cada tecla digitada
autoCapitalize="words" // none | sentences | words | characters
keyboardType="default" // default | numeric | email-address | phone-pad
returnKeyType="done" // O botão do teclado: done | next | search
onSubmitEditing={() => console.log('Enter pressionado')}
/>
<Text>Você digitou: {nome}</Text>
</View>
);
}
Referência rápida de componentes
| Componente | Equivalente Web | Uso principal |
|---|---|---|
| View | <div> | Container, layout com Flexbox |
| Text | <p> / <span> | Todo texto visível na tela |
| Image | <img> | Imagens locais e remotas |
| TextInput | <input type="text"> | Campos de texto editáveis |
| ScrollView | <div> com overflow-y | Conteúdo rolável (listas pequenas) |
| FlatList | — (virtualizado) | Listas longas com performance |
| TouchableOpacity | <button> | Qualquer elemento tocável |
| SafeAreaView | — (nativo) | Evita a "franjinha" do iPhone |
useState e useEffect, que são o coração de qualquer
app React Native interativo. Isso está na Apostila 02.