View, Text, Image и стили: чем RN отличается от вёрстки в вебе

Базовый практический вопрос: чем вёрстка в React Native отличается от привычного HTML и CSS.

В React Native нет DOM, каскада и наследования стилей. Есть небольшой набор нативных компонентов и объект стилей, который применяется только к тому элементу, на который вы его повесили.

Вопрос

«Назовите базовые компоненты React Native. Чем стилизация отличается от CSS? Зачем StyleSheet.create, если можно передать обычный объект?»

Что на самом деле проверяет интервьюер

Не заучены ли у вас веб-привычки. Разработчики, пришедшие из React для браузера, регулярно пытаются использовать проценты во всех измерениях, наследовать шрифты от родителя и ставить position: fixed. Быстро видно, писал ли человек реальные экраны.

Развёрнутый ответ

Минимальный набор компонентов

КомпонентНазначениеВеб-аналог
Viewконтейнер, блок компоновкиdiv
Textединственный способ показать текстspan и p
Imageкартинка из сети или из бандлаimg
ScrollViewпрокручиваемая область (рендерит всё сразу)overflow: scroll
FlatListвиртуализированный список
Pressableлюбая нажимаемая областьbutton
TextInputполе вводаinput

Стили — это объекты

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

export default function PriceTag({ title, price }) {
  return (
    <View style={styles.card}>
      <Text style={styles.title}>{title}</Text>
      <Text style={[styles.price, price === 0 && styles.free]}>
        {price === 0 ? 'Бесплатно' : price + ' руб.'}
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  card: { padding: 16, borderRadius: 12, backgroundColor: '#fff' },
  title: { fontSize: 16, fontWeight: '600' },
  price: { fontSize: 14, color: '#333' },
  free: { color: 'green' },
});

Массив в style — это способ композиции: значения сливаются слева направо, false и undefined просто игнорируются. Это замена условным классам из веба.

Зачем StyleSheet.create

Главное — не производительность (в современных версиях разница минимальна), а инженерные плюсы: стили создаются один раз вне рендера, поэтому не порождают новые ссылки на каждом рендере и не ломают React.memo; плюс появляется проверка типов и подсветка опечаток в TypeScript. Ответ «create даёт стабильную ссылку на объект стиля» звучит убедительнее, чем миф про «отправку стилей через bridge один раз».

Чем стили отличаются от CSS

  • Нет каскада и наследования. Единственное исключение — Text внутри Text: вложенный текст наследует шрифт и цвет.
  • Нет единиц измерения. Числа — это density-independent pixels, а не CSS-пиксели. Проценты работают только у части свойств.
  • Свои имена свойств. camelCase: backgroundColor, marginTop. Короткой записи margin: 0 auto нет.
  • Другой набор. Нет float, z-index работает иначе, position бывает только relative и absolute.

Flexbox в RN: три отличия от веба

  1. flexDirection по умолчанию column, а не row.
  2. alignContent по умолчанию flex-start, а flexShrink — 0 (в вебе 1). Отсюда классическая проблема «длинный текст вылезает за карточку»: нужно явно flexShrink: 1.
  3. Каждый View — это уже flex-контейнер, отдельного display: flex не требуется.
const styles = StyleSheet.create({
  row: { flexDirection: 'row', alignItems: 'center', gap: 8 },
  // без flexShrink длинное имя вытолкнет цену за границу экрана
  name: { flexShrink: 1 },
  price: { marginLeft: 'auto' },
});

Image: размеры обязательны

// локальный ресурс: размеры известны при сборке
<Image source={require('./logo.png')} />

// сетевая картинка: без width и height не будет видна
<Image
  source={{ uri: 'https://example.com/avatar.jpg' }}
  style={{ width: 48, height: 48, borderRadius: 24 }}
  resizeMode="cover"
/>

Полезно упомянуть resizeMode (cover, contain, stretch) и то, что для списков с большим количеством картинок обычно берут expo-image или react-native-fast-image — ради кэширования и плавной подгрузки.

Типичные ошибки кандидатов

  • Пишут строки прямо во View — в RN это ошибка рантайма, а не косметическая проблема.
  • Верят, что fontFamily с родительского View наследуется дочерним текстом. Не наследуется.
  • Используют ScrollView для списка на тысячу элементов: он рендерит всё сразу и съедает память.
  • Не знают, что flexDirection по умолчанию column, — это буквально первый вопрос на вёрстку.

Как ответить кратко

«Базовые кирпичи — View, Text, Image, ScrollView, FlatList, Pressable, TextInput. Стили — это обычные JS-объекты, без каскада и наследования, кроме вложенного Text; единиц измерения нет, свойства в camelCase. StyleSheet.create даёт стабильную ссылку на объект стиля и типизацию, поэтому не ломает React.memo. Flexbox тот же, но flexDirection по умолчанию column, flexShrink равен нулю, а каждый View уже flex-контейнер. Сетевой картинке обязательно нужны явные размеры.»

Проверьте себя
1. Какое значение flexDirection используется в React Native по умолчанию?
Arow, как в вебе
Bcolumn
Crow-reverse
DЗависит от платформы: row на iOS и column на Android
2. Почему текст нельзя положить прямо во View?
AМожно, просто он не будет стилизован
BЛюбая строка обязана находиться внутри компонента Text — иначе рантайм выбросит ошибку
CView не поддерживает вложенные компоненты
DТекст во View отображается только на Android
3. Что произойдёт с картинкой из сети, если у Image не задать width и height?
AОна возьмёт собственные размеры, как тег img в вебе
BОна не будет видна, потому что размеры удалённой картинки заранее неизвестны
CОна растянется на весь экран
DReact Native подставит размеры 100 на 100 пикселей