Desenvolvimento de Aplicativos React Native em 2026: Guia Completo e Perguntas de Entrevista

Domine o desenvolvimento de aplicativos React Native em 2026 com a Nova Arquitetura, Hermes V1 e Fabric. Inclui exemplos de código práticos e perguntas de entrevista técnicas.

Desenvolvimento de aplicativos React Native em 2026

O desenvolvimento de aplicativos React Native em 2026 mudou fundamentalmente com a versão 0.87 que agora inclui a Nova Arquitetura como única opção disponível. A antiga bridge que serializava cada chamada JavaScript-para-nativo em JSON desapareceu, substituída por JSI (JavaScript Interface) para comunicação síncrona direta.

O Que Mudou no React Native 0.87

React Native 0.87 torna a Nova Arquitetura obrigatória. A antiga bridge foi completamente removida. A renderização de listas complexas é 43% mais rápida, as quedas de frames durante o scroll diminuíram 95%, e o uso de memória caiu 33% nos testes de benchmark.

Entendendo JSI e a Nova Arquitetura

JSI (JavaScript Interface) substitui a bridge assíncrona por bindings C++ diretos entre JavaScript e código nativo. Em vez de serializar dados para JSON, passá-los por uma fila de mensagens e desserializar do outro lado, JSI permite que JavaScript mantenha referências a objetos nativos e chame seus métodos diretamente.

Essa mudança arquitetural habilita três capacidades fundamentais: chamadas nativas síncronas, propriedade compartilhada de objetos entre as camadas JavaScript e nativa, e carregamento lazy de módulos nativos.

NativeUserModule.tstypescript
import { TurboModuleRegistry, TurboModule } from 'react-native';

export interface Spec extends TurboModule {
  getUserProfile(userId: string): Promise<{
    id: string;
    name: string;
    email: string;
  }>;
  
  // Synchronous call - only possible with JSI
  getDeviceLocale(): string;
}

export default TurboModuleRegistry.getEnforcing<Spec>('UserModule');

O método getDeviceLocale() retorna imediatamente sem aguardar uma Promise. Isso era impossível com a antiga bridge onde cada chamada nativa exigia serialização assíncrona.

Construindo um Componente de Produção com Fabric

Fabric é o novo sistema de renderização que funciona junto ao JSI. Ele gerencia a árvore de UI em C++ e sincroniza diretamente com a thread JavaScript, eliminando os "travamentos de UI" que ocorriam quando a antiga bridge ficava atrasada durante atualizações rápidas.

ProductCard.tsxtypescript
import React, { memo, useCallback } from 'react';
import {
  View,
  Text,
  Image,
  Pressable,
  StyleSheet,
} from 'react-native';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';

interface Product {
  id: string;
  name: string;
  price: number;
  imageUrl: string;
  inStock: boolean;
}

interface ProductCardProps {
  product: Product;
  onPress: (id: string) => void;
}

const AnimatedPressable = Animated.createAnimatedComponent(Pressable);

export const ProductCard = memo(function ProductCard({
  product,
  onPress,
}: ProductCardProps) {
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const handlePressIn = useCallback(() => {
    scale.value = withSpring(0.95);
  }, [scale]);

  const handlePressOut = useCallback(() => {
    scale.value = withSpring(1);
  }, [scale]);

  const handlePress = useCallback(() => {
    onPress(product.id);
  }, [onPress, product.id]);

  return (
    <AnimatedPressable
      style={[styles.card, animatedStyle]}
      onPressIn={handlePressIn}
      onPressOut={handlePressOut}
      onPress={handlePress}
      accessibilityRole="button"
      accessibilityLabel={`${product.name}, ${product.price} dollars`}
    >
      <Image
        source={{ uri: product.imageUrl }}
        style={styles.image}
        resizeMode="cover"
      />
      <View style={styles.content}>
        <Text style={styles.name} numberOfLines={2}>
          {product.name}
        </Text>
        <Text style={styles.price}>${product.price.toFixed(2)}</Text>
        {!product.inStock && (
          <Text style={styles.outOfStock}>Out of Stock</Text>
        )}
      </View>
    </AnimatedPressable>
  );
});

const styles = StyleSheet.create({
  card: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    overflow: 'hidden',
    marginHorizontal: 8,
    marginVertical: 4,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  image: {
    width: '100%',
    height: 160,
  },
  content: {
    padding: 12,
  },
  name: {
    fontSize: 16,
    fontWeight: '600',
    color: '#1a1a1a',
    marginBottom: 4,
  },
  price: {
    fontSize: 18,
    fontWeight: '700',
    color: '#2563eb',
  },
  outOfStock: {
    fontSize: 12,
    color: '#dc2626',
    marginTop: 4,
  },
});

Este componente usa react-native-reanimated que executa animações na thread de UI via JSI. Os hooks useSharedValue e useAnimatedStyle comunicam diretamente com o código nativo sem passar pela bridge.

Gerenciamento de Estado com TanStack Query

O estado do servidor em aplicações React Native se beneficia de ferramentas dedicadas. TanStack Query gerencia cache, atualização em background e atualizações otimistas sem requerer um container de estado global.

hooks/useProducts.tstypescript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

interface Product {
  id: string;
  name: string;
  price: number;
  imageUrl: string;
  inStock: boolean;
}

const API_BASE = 'https://api.example.com';

async function fetchProducts(category?: string): Promise<Product[]> {
  const url = category
    ? `${API_BASE}/products?category=${category}`
    : `${API_BASE}/products`;
  
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error('Failed to fetch products');
  }
  return response.json();
}

export function useProducts(category?: string) {
  return useQuery({
    queryKey: ['products', category],
    queryFn: () => fetchProducts(category),
    staleTime: 5 * 60 * 1000, // 5 minutes
    gcTime: 30 * 60 * 1000, // 30 minutes
  });
}

export function useToggleStock() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (productId: string) => {
      const response = await fetch(`${API_BASE}/products/${productId}/toggle-stock`, {
        method: 'POST',
      });
      if (!response.ok) {
        throw new Error('Failed to update stock');
      }
      return response.json();
    },
    // Optimistic update
    onMutate: async (productId) => {
      await queryClient.cancelQueries({ queryKey: ['products'] });
      
      const previousProducts = queryClient.getQueryData<Product[]>(['products']);
      
      queryClient.setQueryData<Product[]>(['products'], (old) =>
        old?.map((p) =>
          p.id === productId ? { ...p, inStock: !p.inStock } : p
        )
      );
      
      return { previousProducts };
    },
    onError: (_err, _productId, context) => {
      if (context?.previousProducts) {
        queryClient.setQueryData(['products'], context.previousProducts);
      }
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['products'] });
    },
  });
}

O callback onMutate realiza uma atualização otimista antes que o servidor responda. Se a mutação falhar, onError restaura o estado anterior. Esse padrão fornece feedback visual instantâneo enquanto mantém a consistência dos dados.

Pronto para mandar bem nas entrevistas de React Native?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Expo Router fornece roteamento baseado em arquivos para React Native, similar ao Next.js App Router. A estrutura de arquivos define as rotas automaticamente.

app/(tabs)/_layout.tsxtypescript
import { Tabs } from 'expo-router';
import { Home, Search, ShoppingCart, User } from 'lucide-react-native';

export default function TabsLayout() {
  return (
    <Tabs
      screenOptions={{
        tabBarActiveTintColor: '#2563eb',
        tabBarInactiveTintColor: '#6b7280',
        headerShown: false,
      }}
    >
      <Tabs.Screen
        name="index"
        options={{
          title: 'Home',
          tabBarIcon: ({ color, size }) => (
            <Home color={color} size={size} />
          ),
        }}
      />
      <Tabs.Screen
        name="search"
        options={{
          title: 'Search',
          tabBarIcon: ({ color, size }) => (
            <Search color={color} size={size} />
          ),
        }}
      />
      <Tabs.Screen
        name="cart"
        options={{
          title: 'Cart',
          tabBarIcon: ({ color, size }) => (
            <ShoppingCart color={color} size={size} />
          ),
        }}
      />
      <Tabs.Screen
        name="profile"
        options={{
          title: 'Profile',
          tabBarIcon: ({ color, size }) => (
            <User color={color} size={size} />
          ),
        }}
      />
    </Tabs>
  );
}

Rotas dinâmicas usam notação de colchetes. Um arquivo em app/product/[id].tsx manipula qualquer caminho /product/123:

app/product/[id].tsxtypescript
import { useLocalSearchParams } from 'expo-router';
import { View, Text, ActivityIndicator } from 'react-native';
import { useQuery } from '@tanstack/react-query';

export default function ProductDetailScreen() {
  const { id } = useLocalSearchParams<{ id: string }>();

  const { data: product, isLoading, error } = useQuery({
    queryKey: ['product', id],
    queryFn: () => fetchProduct(id),
    enabled: !!id,
  });

  if (isLoading) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <ActivityIndicator size="large" color="#2563eb" />
      </View>
    );
  }

  if (error || !product) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>Product not found</Text>
      </View>
    );
  }

  return (
    <View style={{ flex: 1, padding: 16 }}>
      <Text style={{ fontSize: 24, fontWeight: 'bold' }}>{product.name}</Text>
      <Text style={{ fontSize: 20, color: '#2563eb' }}>
        ${product.price.toFixed(2)}
      </Text>
    </View>
  );
}

Perguntas de Entrevista Comuns sobre Arquitetura React Native

Entrevistas técnicas para posições de React Native em 2026 focam fortemente na Nova Arquitetura. As seguintes perguntas aparecem frequentemente.

Áreas de Foco em Entrevistas

Entrevistadores esperam que candidatos expliquem JSI, Fabric e TurboModules em nível conceitual. Memorizar sintaxe importa menos do que entender por que a arquitetura mudou e quais problemas ela resolve.

Pergunta: O que é JSI e por que React Native o adotou?

JSI (JavaScript Interface) é uma camada C++ que permite que JavaScript mantenha referências a objetos nativos e chame seus métodos diretamente. A antiga bridge serializava cada chamada para JSON, enfileirava assincronamente, e desserializava no lado nativo. Isso adicionava latência e prevenia operações síncronas.

Com JSI, uma função JavaScript pode chamar um método nativo e receber o resultado no mesmo frame. Isso habilita funcionalidades como medições de layout síncronas e manipulação direta de views nativas.

Pergunta: Como Fabric difere do antigo renderer?

Fabric é um sistema de renderização C++ que mantém a árvore de UI em código nativo ao invés de JavaScript. O antigo renderer mantinha a shadow tree em JavaScript e enviava lotes de atualizações através da bridge.

Benefícios do Fabric:

  • Cálculos de layout síncronos via JSI
  • Suporte a renderização concorrente (funcionalidades do React 18 funcionam corretamente)
  • Melhor gerenciamento de memória com propriedade compartilhada entre JS e nativo
  • Redução do overhead de serialização

Pergunta: O que são TurboModules?

TurboModules substituem os Native Modules. As diferenças principais:

  1. Carregamento lazy: TurboModules carregam apenas quando acessados pela primeira vez, reduzindo tempo de inicialização
  2. Type safety: CodeGen gera bindings tipados a partir de especificações TypeScript
  3. Métodos síncronos: TurboModules podem expor funções síncronas quando necessário
  4. Acesso JSI direto: Sem serialização da bridge

Pergunta: Quando usar um método nativo síncrono?

Métodos nativos síncronos são apropriados para operações que:

  • Completam em microssegundos (ler locale do dispositivo, verificar status de permissões)
  • Bloqueiam a UI intencionalmente (confirmação modal antes de navegação)
  • Retornam valores necessários para renderização imediata

Evitar métodos síncronos para:

  • Requisições de rede
  • I/O de arquivos além de pequenas leituras
  • Consultas de banco de dados
  • Qualquer operação que exceda 16ms (bloqueia o frame)

Para mais perguntas de entrevista sobre React Native, consulte o módulo de networking e API e a seção de módulos nativos.

Testando Componentes React Native

React Native Testing Library fornece utilitários para testar componentes como os usuários interagem com eles, focando em acessibilidade e comportamento ao invés de detalhes de implementação.

__tests__/ProductCard.test.tsxtypescript
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react-native';
import { ProductCard } from '../components/ProductCard';

const mockProduct = {
  id: 'prod-1',
  name: 'Wireless Headphones',
  price: 149.99,
  imageUrl: 'https://example.com/headphones.jpg',
  inStock: true,
};

describe('ProductCard', () => {
  it('displays product information', () => {
    const onPress = jest.fn();
    render(<ProductCard product={mockProduct} onPress={onPress} />);

    expect(screen.getByText('Wireless Headphones')).toBeOnTheScreen();
    expect(screen.getByText('$149.99')).toBeOnTheScreen();
  });

  it('calls onPress with product id when pressed', () => {
    const onPress = jest.fn();
    render(<ProductCard product={mockProduct} onPress={onPress} />);

    fireEvent.press(
      screen.getByRole('button', { name: /wireless headphones/i })
    );

    expect(onPress).toHaveBeenCalledWith('prod-1');
    expect(onPress).toHaveBeenCalledTimes(1);
  });

  it('shows out of stock message when product unavailable', () => {
    const outOfStockProduct = { ...mockProduct, inStock: false };
    render(<ProductCard product={outOfStockProduct} onPress={jest.fn()} />);

    expect(screen.getByText('Out of Stock')).toBeOnTheScreen();
  });
});

Os testes consultam por conteúdo de texto e roles de acessibilidade ao invés de test IDs ou internos do componente. Esta abordagem detecta regressões que afetam usuários enquanto permanece resistente a refatorações.

Monitoramento de Performance em Produção

React Native 0.87 integra com Sentry e ferramentas similares para monitoramento de performance em produção. Métricas chave para acompanhar:

  • Time to Interactive (TTI): Tempo até o app responder a interação do usuário
  • Quedas de frames: Frames que levam mais de 16.67ms para renderizar
  • Uso da thread JavaScript: Alto uso indica cálculos custosos bloqueando a UI
  • Crescimento de memória: Aumentos constantes sugerem vazamentos
app/_layout.tsxtypescript
import * as Sentry from '@sentry/react-native';
import { useEffect } from 'react';
import { AppState, AppStateStatus } from 'react-native';

Sentry.init({
  dsn: process.env.EXPO_PUBLIC_SENTRY_DSN,
  tracesSampleRate: 0.2,
  profilesSampleRate: 0.1,
  enableAutoPerformanceTracing: true,
});

export default function RootLayout() {
  useEffect(() => {
    const subscription = AppState.addEventListener(
      'change',
      (state: AppStateStatus) => {
        if (state === 'active') {
          Sentry.addBreadcrumb({
            category: 'app.lifecycle',
            message: 'App became active',
            level: 'info',
          });
        }
      }
    );

    return () => subscription.remove();
  }, []);

  // ... rest of layout
}

Pontos-Chave para Desenvolvimento React Native em 2026

  • A Nova Arquitetura (JSI, Fabric, TurboModules) é obrigatória no React Native 0.87. A antiga bridge não existe mais.
  • JSI habilita chamadas nativas síncronas. Usá-las com parcimônia para operações abaixo de 16ms.
  • Fabric renderiza a UI em C++ e sincroniza com JavaScript via JSI. Isso elimina o gargalo da renderização assíncrona.
  • TurboModules carregam de forma lazy e fornecem bindings tipados gerados a partir de specs TypeScript.
  • Expo Router oferece navegação baseada em arquivos similar ao Next.js App Router.
  • React Native Testing Library testa componentes através de sua API pública e árvore de acessibilidade.
  • Aplicações em produção devem rastrear TTI, quedas de frames e uso de memória desde o primeiro dia.

Para uma visão mais aprofundada da construção de aplicações completas, consulte o tutorial de aplicação completa React Native. O guia da Nova Arquitetura cobre a migração de versões anteriores.

Comece a praticar!

Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.

Desafio do dia

Você saberia encontrar o bug em React Native?

Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador da SharpSkill

Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.

Atualizado em 6 de setembro de 2026

Tags

#react-native
#mobile-development
#javascript
#typescript
#new-architecture

Compartilhar

Artigos relacionados