Version1

Від React до React Native: ключові відмінності

Систематичне порівняння React (веб) та React Native — DOM проти нативних компонентів, CSS проти StyleSheet, події, платформо-залежна поведінка та перший живий приклад у браузері.

Від React до React Native: ключові відмінності

Те, що ви вже знаєте — і те, що зміниться

Якщо ви пишете на React, ваші знання не зникають — вони переносяться. Компонентна модель, хуки, JSX, однонаправлений потік даних, TypeScript — все це залишається незмінним. Але React Native — це інша платформа, і вона диктує інші правила для UI-рівня.

Уявіть аналогію: ви програміст, який знає алгоритми і структури даних. Ці знання універсальні — вони однаково застосовуються у Python, Go чи Rust. Але синтаксис, стандартна бібліотека, інструменти — різні. Так само і тут: React — це «алгоритми», а React Native — нова «мова» для мобільної платформи.

У цій статті ми систематично пройдемо всі ключові відмінності — від концептуальних до практичних. До кінця у вас буде чіткий «словник перекладу» з React у React Native.


Відмінність 1: DOM не існує

Що таке DOM у веб-React

У браузері React рендерить компоненти у Document Object Model (DOM) — деревоподібну структуру HTML-елементів, якою керує браузер. Коли ви пишете <div className="container">, React створює вузол DOM-дерева, браузер малює його на екрані відповідно до CSS-правил.

App.tsx — React (веб)
// Веб React: JSX → Virtual DOM → реальний DOM
function App() {
    return (
        <div className="container">
            <h1>Заголовок</h1>
            <p>Параграф тексту</p>
            <button onClick={() => alert('Привіт!')}>Натисни</button>
        </div>
    )
}

Браузер розуміє <div>, <h1>, <p>, <button> — це стандарт HTML, визначений специфікацією W3C.

Що відбувається у React Native

React Native не має браузера. Він виконується безпосередньо на iOS або Android. Тому він не знає, що таке <div> або <p>. Замість DOM він використовує нативні компоненти — JavaScript-обгортки над платформо-специфічними елементами UI:

  • На iOS <View> стає UIView (UIKit)
  • На Android <View> стає android.view.View
  • На iOS <Text> стає UILabel
  • На Android <Text> стає TextView
App.tsx — React Native
// React Native: JSX → Shadow Tree → нативні UIView/View
import { View, Text, Pressable } from 'react-native'

function App() {
    return (
        <View style={styles.container}>
            <Text style={styles.heading}>Заголовок</Text>
            <Text>Параграф тексту</Text>
            <Pressable onPress={() => alert('Привіт!')}>
                <Text>Натисни</Text>
            </Pressable>
        </View>
    )
}
Критичне правило: у React Native неможливо використовувати HTML-елементи. <div>, <span>, <p>, <input>, <button> — всі вони викличуть помилку. Завжди імпортуйте компоненти з 'react-native' або з Expo/community-бібліотек.

Повна таблиця відповідностей: HTML → React Native

HTML (веб)React NativeПримітки
<div><View>Основний контейнер для layout
<span><Text>Але Text — блоковий, не рядковий
<p><Text>Немає семантичного аналога
<h1>...<h6><Text style={...}>Розмір через style, не тег
<button><Pressable> або <TouchableOpacity>Нема нативної кнопки-контейнера
<input type="text"><TextInput>
<input type="checkbox"><Switch> або community Checkbox
<img><Image>Обов'язкові width/height для мережевих
<ul> / <li><FlatList> або <View> + mapFlatList для довгих списків
<select><Picker> (community)Окремий пакет
<a><Pressable> + LinkingНемає href
<form><View> + станНемає нативних форм
<iframe><WebView> (community)Окремий пакет
<video><Video> (expo-av)
<canvas><Canvas> (react-native-skia)
<svg>react-native-svg
<table><FlatList> / кастомна таблицяНемає нативного аналога
Чому немає семантичних тегів? У вебі <h1>, <nav>, <article> несуть семантику для пошукових систем та screen readers. У мобільних застосунках доступність реалізована через accessibility props (accessibilityRole, accessibilityLabel), а не через теги. Тому React Native обходиться мінімальним набором компонентів.

Відмінність 2: CSS не існує — є StyleSheet

Що зникає разом з DOM

У браузері стилі — це CSS: каскад, специфічність, псевдокласи, медіазапити, анімації через @keyframes, Grid, Float, селектори. React Native не має жодного з цього. Причина проста: немає браузерного движка, немає CSS-парсера.

Натомість React Native використовує StyleSheet — JavaScript-об'єкт зі стилями, який за синтаксисом нагадує CSS, але є лише його невеликою підмножиною.

import { View, Text, StyleSheet } from 'react-native'

function Card() {
    return (
        <View style={styles.card}>
            <Text style={styles.title}>Заголовок</Text>
            <Text style={styles.body}>Текст картки</Text>
        </View>
    )
}

const styles = StyleSheet.create({
    card: {
        backgroundColor: '#ffffff',
        borderRadius: 12,
        padding: 16,
        // Тінь на iOS:
        shadowColor: '#000',
        shadowOffset: { width: 0, height: 2 },
        shadowOpacity: 0.1,
        shadowRadius: 4,
        // Тінь на Android (elevation):
        elevation: 3,
    },
    title: {
        fontSize: 18,
        fontWeight: '700',
        color: '#1a1a1a',
        marginBottom: 8,
    },
    body: {
        fontSize: 14,
        color: '#666666',
        lineHeight: 20,
    },
})

Що є у StyleSheet, чого немає в CSS, і навпаки

CSS-властивості, які ДОСТУПНІ у React Native (з відмінностями):

CSSReact Native StyleSheetВідмінність
background-color: redbackgroundColor: 'red'camelCase, рядкове значення
font-size: 16pxfontSize: 16Без одиниць, числове значення
margin: 10px 20pxmarginVertical: 10, marginHorizontal: 20Немає shorthand-синтаксису
border: 1px solid #cccborderWidth: 1, borderColor: '#ccc'Немає shorthand
border-radius: 8pxborderRadius: 8
display: flexЗа замовчуванням (Flexbox увімкнений завжди)Немає display: block/inline/grid
flex-direction: rowflexDirection: 'row'За замовч. 'column', а не 'row'!
opacity: 0.5opacity: 0.5Однаково
overflow: hiddenoverflow: 'hidden'
position: absoluteposition: 'absolute'Немає fixed, sticky
z-index: 10zIndex: 10

CSS-можливості, яких у React Native НЕМАЄ зовсім:

CSS-концепціяПричина відсутностіАльтернатива у RN
::before, ::afterНемає CSS-парсераДодатковий <View>
:hover, :focusНемає мишіonPressIn, onFocus props
@media (медіазапити)useWindowDimensions hook
@keyframesAnimated API або Reanimated
display: gridFlexbox з numColumns у FlatList
float: leftFlexbox flexDirection: 'row'
position: fixedАбсолютне позиціонування + SafeAreaView
position: stickystickyHeaderIndices у ScrollView
CSS GridFlexbox
CSS VariablesJS constants або Theme Context
CSS-селекториProps та стиль на кожен компонент
Каскад (cascade)Явна передача стилів через props
Класи (className)style prop
Головна ментальна модель: StyleSheet у React Native — це Flexbox + підмножина CSS. Якщо ви знаєте Flexbox, ви вже знаєте 80% того, що потрібно для layout у React Native. Для всього іншого: там, де у CSS є каскад і селектори — у RN є явна передача style prop.

Чому StyleSheet.create(), а не звичайний об'єкт?

Технічно можна писати стилі як звичайний JS-об'єкт:

// Це теж працює, але не рекомендується:
<View style={{ backgroundColor: 'red', padding: 16 }}>

Але StyleSheet.create() має переваги:

  1. Перевірка типів — TypeScript підкаже, якщо ви напишете неправильну властивість
  2. Оптимізація — у New Architecture стилі реєструються один раз і передаються за ID, а не копіюються щоразу
  3. Читабельність — стилі відокремлені від розмітки, як у CSS-in-JS бібліотеках

Відмінність 3: Обробка подій

onClick → onPress (і набагато більше)

У вебі майже всі інтерактивні елементи отримують події через onClick. На мобільному пристрої немає миші — є дотик (touch). Це породжує іншу модель подій:

onClick → onPress

Основний обробник дотику. Спрацьовує після завершення натискання (аналог mouseup). Доступний на Pressable, TouchableOpacity, Button.

<Pressable onPress={() => console.log('натиснуто')}>
    <Text>Кнопка</Text>
</Pressable>

onPressIn / onPressOut

Спрацьовують на початку та кінці дотику (аналоги mousedown/mouseup). Використовуються для анімацій натискання — змінити стиль «під час натискання».

<Pressable
  onPressIn={() => setScale(0.95)}
  onPressOut={() => setScale(1)}
>

onLongPress

Спрацьовує після утримання дотику (за замовч. 500 мс). Типовий мобільний патерн: «довге натискання відкриває контекстне меню».

<Pressable onLongPress={() => showContextMenu()}>

onChangeText (TextInput)

Аналог onChange для текстових полів. Але отримує вже готовий рядок string, а не event об'єкт. Не потрібно event.target.value.

<TextInput onChangeText={(text) => setValue(text)} />

Повна таблиця відповідностей подій

Веб-подіяReact NativeКомпонент
onClickonPressPressable, TouchableOpacity
onMouseDownonPressInPressable
onMouseUponPressOutPressable
onDoubleClick(немає стандартного)Gesture Handler: Tap({ count: 2 })
onChange (input)onChangeTextTextInput
onFocusonFocusTextInput
onBluronBlurTextInput
onScrollonScrollScrollView, FlatList
onSubmit (form)onSubmitEditingTextInput
onKeyDown(обмежено)TextInput: onKeyPress
Жести мишіGesturesreact-native-gesture-handler

Відмінність 4: Браузерні API зникають

React Native виконується поза браузером, тому всі window.*, document.* та подібні API недоступні. Ось повна таблиця замін:

Браузерний APIReact Native аналогПакет
localStorageAsyncStorage@react-native-async-storage/async-storage
sessionStorageAsyncStorage (або пам'ять)
fetch()fetch()вбудований у RN
navigator.geolocationexpo-locationexpo-location
Notification APIexpo-notificationsexpo-notifications
navigator.mediaDevices.getUserMediaexpo-cameraexpo-camera
window.open(url)Linking.openURL(url)вбудований Linking
window.alert()Alert.alert()вбудований Alert
window.innerWidth/HeightuseWindowDimensions()вбудований хук
document.title<Stack.Screen options={{ title }}>expo-router
history.pushState()router.push()expo-router
WebSocketWebSocketвбудований у RN
Canvas APIreact-native-skia@shopify/react-native-skia
clipboard APIexpo-clipboardexpo-clipboard
fetch — виняток:fetch() є у React Native «з коробки» і поводиться так само, як у браузері. Це один з небагатьох браузерних API, що доступний напряму. XMLHttpRequest також підтримується (але рідко використовується — зазвичай через Axios або RTK Query).

Відмінність 5: Платформо-залежна поведінка iOS vs Android

На відміну від веб-браузерів, де є стандарт (W3C), iOS і Android — це дві різні платформи з різними конвенціями, шрифтами і поведінкою UI. React Native намагається надати єдиний API, але деякі речі різняться:

const styles = StyleSheet.create({
    box: {
        // iOS — через shadow-властивості:
        shadowColor: '#000',
        shadowOffset: { width: 0, height: 4 },
        shadowOpacity: 0.15,
        shadowRadius: 6,

        // Android — через elevation:
        elevation: 5,

        // Обидва на одному компоненті — кожна
        // платформа використовує своє:
        backgroundColor: '#fff', // обов'язково для iOS shadow
    },
})

Перший живий приклад: React Native у браузері

Завдяки компоненту ::react-native-preview ви можете побачити React Native компоненти прямо у браузері — вони рендеряться через react-native-web. Це не повноцінний емулятор, але достатньо для розуміння базових концепцій UI.

TSXApp.tsx
iPhone
9:41

Loading…

react-native-web · not a real device

Зверніть на декілька речей у цьому прикладі:

  1. Немає <div> чи <button> — лише <View>, <Text>, <Pressable> з react-native
  2. Стан (useState) — ідентичний веб-React, жодних відмінностей
  3. StyleSheet.create() — всі стилі зосереджені внизу, stilo CSS-in-JS
  4. pressed станonPressIn/onPressOut дозволяють змінювати стиль «під час натискання» — це мобільний аналог CSS :active
  5. [styles.button, pressed && styles.buttonPressed] — масив стилів, де другий перекриває перший

Практика

Copyright © 2026