Tworzenie Aplikacji React Native w 2026: Kompletny Przewodnik i Pytania Rekrutacyjne
Poznaj tworzenie aplikacji React Native w 2026 roku z Nową Architekturą, JSI, Fabric i TurboModules. Praktyczny tutorial z przykładami kodu i pytaniami na rozmowę kwalifikacyjną.

Tworzenie aplikacji React Native w 2026 roku przeszło fundamentalną transformację wraz z wersją 0.87, która wprowadza Nową Architekturę jako jedyną obsługiwaną opcję. Stary bridge, który serializował każde wywołanie JavaScript-do-native jako JSON, został całkowicie usunięty i zastąpiony przez JSI (JavaScript Interface) umożliwiający bezpośrednią, synchroniczną komunikację.
React Native 0.87 czyni Nową Architekturę obowiązkową. Stary bridge został całkowicie usunięty. Renderowanie złożonych list działa o 43% szybciej, spadki klatek podczas przewijania zmniejszyły się o 95%, a wykorzystanie pamięci spadło o 33% w testach wydajnościowych.
Zrozumienie JSI i Nowej Architektury
JSI (JavaScript Interface) zastępuje asynchroniczny bridge bezpośrednimi wiązaniami C++ między JavaScript a kodem natywnym. Zamiast serializować dane do JSON, przekazywać je przez kolejkę komunikatów i deserializować po drugiej stronie, JSI pozwala JavaScript przechowywać referencje do obiektów natywnych i wywoływać ich metody bezpośrednio.
Ta zmiana architektoniczna umożliwia trzy kluczowe możliwości: synchroniczne wywołania natywne, współdzielone posiadanie obiektów między warstwami JavaScript i natywną oraz leniwe ładowanie modułów natywnych.
import { TurboModuleRegistry, TurboModule } from 'react-native';
export interface Spec extends TurboModule {
getUserProfile(userId: string): Promise<{
id: string;
name: string;
email: string;
}>;
// Wywołanie synchroniczne - możliwe tylko z JSI
getDeviceLocale(): string;
}
export default TurboModuleRegistry.getEnforcing<Spec>('UserModule');Metoda getDeviceLocale() zwraca wynik natychmiast bez oczekiwania na Promise. Było to niemożliwe ze starym bridge, gdzie każde wywołanie natywne wymagało asynchronicznej serializacji.
Budowanie Komponentu Produkcyjnego z Fabric
Fabric to nowy system renderowania działający obok JSI. Zarządza drzewem UI w C++ i synchronizuje się bezpośrednio z wątkiem JavaScript, eliminując "zacinanie się UI", które występowało gdy stary bridge pozostawał w tyle podczas szybkich aktualizacji.
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} złotych`}
>
<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)} zł</Text>
{!product.inStock && (
<Text style={styles.outOfStock}>Brak w magazynie</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,
},
});Ten komponent używa react-native-reanimated, który uruchamia animacje na wątku UI przez JSI. Hooki useSharedValue i useAnimatedStyle komunikują się bezpośrednio z kodem natywnym bez przechodzenia przez bridge.
Zarządzanie Stanem z TanStack Query
Stan serwera w aplikacjach React Native korzysta z dedykowanych narzędzi. TanStack Query obsługuje cache'owanie, odświeżanie w tle i optymistyczne aktualizacje bez wymagania globalnego kontenera stanu.
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('Nie udało się pobrać produktów');
}
return response.json();
}
export function useProducts(category?: string) {
return useQuery({
queryKey: ['products', category],
queryFn: () => fetchProducts(category),
staleTime: 5 * 60 * 1000, // 5 minut
gcTime: 30 * 60 * 1000, // 30 minut
});
}
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('Nie udało się zaktualizować stanu magazynowego');
}
return response.json();
},
// Optymistyczna aktualizacja
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'] });
},
});
}Callback onMutate wykonuje optymistyczną aktualizację przed odpowiedzią serwera. Jeśli mutacja się nie powiedzie, onError przywraca poprzedni stan. Ten wzorzec zapewnia natychmiastową reakcję UI przy zachowaniu spójności danych.
Gotowy na rozmowy o React Native?
Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.
Nawigacja z Expo Router
Expo Router zapewnia nawigację opartą na plikach dla React Native, podobnie jak Next.js App Router. Struktura plików automatycznie definiuje trasy.
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: 'Główna',
tabBarIcon: ({ color, size }) => (
<Home color={color} size={size} />
),
}}
/>
<Tabs.Screen
name="search"
options={{
title: 'Szukaj',
tabBarIcon: ({ color, size }) => (
<Search color={color} size={size} />
),
}}
/>
<Tabs.Screen
name="cart"
options={{
title: 'Koszyk',
tabBarIcon: ({ color, size }) => (
<ShoppingCart color={color} size={size} />
),
}}
/>
<Tabs.Screen
name="profile"
options={{
title: 'Profil',
tabBarIcon: ({ color, size }) => (
<User color={color} size={size} />
),
}}
/>
</Tabs>
);
}Dynamiczne trasy używają notacji nawiasów kwadratowych. Plik w app/product/[id].tsx obsługuje dowolną ścieżkę /product/123:
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>Nie znaleziono produktu</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)} zł
</Text>
</View>
);
}Popularne Pytania Rekrutacyjne o Architekturę React Native
Rozmowy kwalifikacyjne na stanowiska React Native w 2026 roku koncentrują się głównie na Nowej Architekturze. Poniższe pytania pojawiają się często.
Rekruterzy oczekują, że kandydaci potrafią wyjaśnić JSI, Fabric i TurboModules na poziomie koncepcyjnym. Zapamiętywanie składni jest mniej istotne niż zrozumienie, dlaczego architektura się zmieniła i jakie problemy rozwiązuje.
Pytanie: Czym jest JSI i dlaczego React Native go przyjął?
JSI (JavaScript Interface) to warstwa C++, która pozwala JavaScript przechowywać referencje do obiektów natywnych i bezpośrednio wywoływać ich metody. Stary bridge serializował każde wywołanie do JSON, kolejkował je asynchronicznie i deserializował po stronie natywnej. To dodawało opóźnienia i uniemożliwiało operacje synchroniczne.
Dzięki JSI funkcja JavaScript może wywołać metodę natywną i otrzymać wynik w tej samej klatce. Umożliwia to funkcje takie jak synchroniczne pomiary układu i bezpośrednia manipulacja widokami natywnymi.
Pytanie: Czym Fabric różni się od starego renderera?
Fabric to system renderowania w C++, który utrzymuje drzewo UI w kodzie natywnym zamiast w JavaScript. Stary renderer przechowywał shadow tree w JavaScript i wysyłał partie aktualizacji przez bridge.
Zalety Fabric:
- Synchroniczne obliczenia układu przez JSI
- Wsparcie dla concurrent rendering (funkcje React 18 działają poprawnie)
- Lepsze zarządzanie pamięcią ze współdzielonym posiadaniem między JS a native
- Zmniejszony narzut serializacji
Pytanie: Czym są TurboModules?
TurboModules to zamiennik Native Modules. Kluczowe różnice:
- Leniwe ładowanie: TurboModules ładują się dopiero przy pierwszym dostępie, skracając czas uruchamiania
- Bezpieczeństwo typów: CodeGen generuje type-safe wiązania ze specyfikacji TypeScript
- Metody synchroniczne: TurboModules mogą eksponować funkcje synchroniczne gdy jest to potrzebne
- Bezpośredni dostęp do JSI: Brak serializacji przez bridge
Pytanie: Kiedy użyć synchronicznej metody natywnej?
Synchroniczne metody natywne nadają się do operacji, które:
- Kończą się w mikrosekundach (odczyt locale urządzenia, sprawdzenie statusu uprawnień)
- Celowo blokują UI (potwierdzenie modalne przed nawigacją)
- Zwracają wartości potrzebne do natychmiastowego renderowania
Należy unikać metod synchronicznych dla:
- Żądań sieciowych
- Operacji I/O na plikach wykraczających poza małe odczyty
- Zapytań do bazy danych
- Każdej operacji przekraczającej 16ms (blokuje klatkę)
Więcej pytań rekrutacyjnych o React Native znajduje się w module networking i API oraz sekcji modułów natywnych.
Testowanie Komponentów React Native
React Native Testing Library dostarcza narzędzia do testowania komponentów tak, jak użytkownicy z nimi interagują, skupiając się na dostępności i zachowaniu zamiast szczegółów implementacji.
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react-native';
import { ProductCard } from '../components/ProductCard';
const mockProduct = {
id: 'prod-1',
name: 'Słuchawki Bezprzewodowe',
price: 149.99,
imageUrl: 'https://example.com/headphones.jpg',
inStock: true,
};
describe('ProductCard', () => {
it('wyświetla informacje o produkcie', () => {
const onPress = jest.fn();
render(<ProductCard product={mockProduct} onPress={onPress} />);
expect(screen.getByText('Słuchawki Bezprzewodowe')).toBeOnTheScreen();
expect(screen.getByText('149.99 zł')).toBeOnTheScreen();
});
it('wywołuje onPress z id produktu po naciśnięciu', () => {
const onPress = jest.fn();
render(<ProductCard product={mockProduct} onPress={onPress} />);
fireEvent.press(
screen.getByRole('button', { name: /słuchawki bezprzewodowe/i })
);
expect(onPress).toHaveBeenCalledWith('prod-1');
expect(onPress).toHaveBeenCalledTimes(1);
});
it('pokazuje komunikat o braku gdy produkt niedostępny', () => {
const outOfStockProduct = { ...mockProduct, inStock: false };
render(<ProductCard product={outOfStockProduct} onPress={jest.fn()} />);
expect(screen.getByText('Brak w magazynie')).toBeOnTheScreen();
});
});Testy odpytują według treści tekstowej i ról dostępności zamiast test ID lub wewnętrznych szczegółów komponentu. To podejście wyłapuje regresje wpływające na użytkowników, pozostając odpornym na refaktoryzację.
Monitorowanie Wydajności w Produkcji
React Native 0.87 integruje się z Sentry i podobnymi narzędziami do monitorowania wydajności produkcyjnej. Kluczowe metryki do śledzenia:
- Time to Interactive (TTI): Jak długo do momentu gdy aplikacja reaguje na input użytkownika
- Spadki klatek: Klatki renderowane dłużej niż 16.67ms
- Wykorzystanie wątku JavaScript: Wysokie użycie wskazuje na kosztowne obliczenia blokujące UI
- Wzrost pamięci: Stały wzrost sugeruje wycieki
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: 'Aplikacja stała się aktywna',
level: 'info',
});
}
}
);
return () => subscription.remove();
}, []);
// ... reszta layoutu
}Kluczowe Wnioski dla Tworzenia Aplikacji React Native w 2026
- Nowa Architektura (JSI, Fabric, TurboModules) jest obowiązkowa w React Native 0.87. Stary bridge już nie istnieje.
- JSI umożliwia synchroniczne wywołania natywne. Należy ich używać oszczędnie dla operacji poniżej 16ms.
- Fabric renderuje UI w C++ i synchronizuje z JavaScript przez JSI. To eliminuje asynchroniczne wąskie gardło renderowania.
- TurboModules ładują się leniwie i dostarczają type-safe wiązania generowane ze specyfikacji TypeScript.
- Expo Router oferuje nawigację opartą na plikach podobną do Next.js App Router.
- React Native Testing Library testuje komponenty przez ich publiczne API i drzewo dostępności.
- Aplikacje produkcyjne powinny śledzić TTI, spadki klatek i wykorzystanie pamięci od pierwszego dnia.
Dla głębszego spojrzenia na budowanie kompletnych aplikacji, zobacz tutorial kompletnej aplikacji React Native. Przewodnik po Nowej Architekturze obejmuje migrację ze starszych wersji.
Zacznij ćwiczyć!
Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.
Znajdziesz błąd w React Native?
Prawdziwy fragment kodu, ukryty błąd, jedna próba dziennie. Bez konta, żeby spróbować.

Autor:
Anthony Fillion-MailletZałożyciel SharpSkill
Programista fullstack od ponad 10 lat. Prowadzi SharpSkill i odpowiada za wszystko, co się tu ukazuje.
Zaktualizowano 6 września 2026
Udostępnij
Powiązane artykuły

Przewodnik po tworzeniu aplikacji React Native 2026: Produkcyjne aplikacje i pytania rekrutacyjne
Kompletny przewodnik po tworzeniu produkcyjnych aplikacji React Native w 2026 roku obejmujący Expo SDK 56, EAS Build, Hermes V1, Nową Architekturę oraz przygotowanie do rozmów kwalifikacyjnych dla programistów React Native.

React Native 0.87 i SwiftPM w 2026: Nowoczesny Build iOS i Pytania Rekrutacyjne
React Native 0.87 wprowadza eksperymentalne wsparcie dla Swift Package Manager, eliminując potrzebę CocoaPods. Poznaj konfigurację SwiftPM, autolinkowanie i przygotuj się do rozmów rekrutacyjnych.

Flutter vs React Native Wydajność 2026: Benchmarki i Pytania Rekrutacyjne
Porównanie wydajności Flutter vs React Native w 2026. Benchmarki Impeller vs New Architecture, zużycie pamięci, FPS i pytania na rozmowy kwalifikacyjne.