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: три отличия от веба
flexDirectionпо умолчанию column, а не row.alignContentпо умолчаниюflex-start, аflexShrink— 0 (в вебе 1). Отсюда классическая проблема «длинный текст вылезает за карточку»: нужно явноflexShrink: 1.- Каждый
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-контейнер. Сетевой картинке обязательно нужны явные размеры.»