React в React Native тот же: компоненты, хуки, пропсы. Отличаются примитивы и стили. Фронтендеры часто спотыкаются как раз об эти отличия, и на собесе их проверяют.
Базовые компоненты
View: контейнер, аналогdiv, но без текста внутри.Text: весь текст обязан быть внутриText. Строка прямо вViewдаст ошибку «Text strings must be rendered within a <Text> component».Image: картинки, для удалённых обязательно указать размеры.TextInput: поле ввода,valueиonChangeText.Pressable: современный способ обработать нажатие, с состояниямиpressed,hovered,onLongPress.TouchableOpacityи другиеTouchable*ещё работают, но новые экраны пишут наPressable.ScrollView: прокрутка, рендерит всех детей сразу. Для длинных данных нуженFlatList.Modal,ActivityIndicator,Switch,KeyboardAvoidingView.
Стили
Стили это объекты JS, свойства в camelCase, числа без единиц (логические пиксели, dp/pt):
const styles = StyleSheet.create({
card: { padding: 16, borderRadius: 12, backgroundColor: '#fff' },
title: { fontSize: 18, fontWeight: '600' },
});
<View style={[styles.card, selected && { borderColor: 'tomato', borderWidth: 2 }]} />
- Массив стилей объединяется слева направо,
falseиnullпропускаются. - Каскада и наследования, как в CSS, почти нет. Наследуется только стиль текста от родительского
Textк вложенномуText.colorуViewне повлияет на текст внутри. StyleSheet.createпроверяет стили и делает код понятнее. Инлайновые объекты создаются заново при каждом рендере, что мешаетmemo-компонентам.
Flexbox в RN
Раскладка через Yoga, почти как в вебе, но умолчания другие:
| Свойство | Веб | React Native |
|---|---|---|
flexDirection | row | column |
alignContent | normal | flex-start |
flexShrink | 1 | 0 |
position | static | relative |
flex: 1 в RN означает «занять всё свободное место по главной оси». Ещё одно отличие: display бывает только flex и none (в новых версиях добавлен contents), нет grid и float.
Платформенные различия
import { Platform } from 'react-native';
const styles = StyleSheet.create({
shadow: Platform.select({
ios: { shadowColor: '#000', shadowOpacity: 0.1, shadowRadius: 8, shadowOffset: { width: 0, height: 2 } },
android: { elevation: 3 },
}),
});
Раньше тени на iOS задавались свойствами shadow*, на Android через elevation. Новые версии поддерживают свойство boxShadow в стиле CSS на обеих платформах (с новой архитектурой). Файлы Button.ios.tsx и Button.android.tsx подхватываются сборщиком автоматически по расширению.
Размеры экрана и safe area
useWindowDimensions() возвращает ширину и высоту окна и обновляется при повороте и изменении размера. Dimensions.get даёт снимок на момент вызова и сам не обновляется. Вырезы, «чёлку» и системные панели учитывают через react-native-safe-area-context (SafeAreaView, useSafeAreaInsets). Встроенный SafeAreaView из react-native работает только на iOS и устарел.
Клавиатура перекрывает поля ввода: KeyboardAvoidingView (на iOS обычно behavior="padding") или библиотеки вроде react-native-keyboard-controller.
Доступность
accessibilityLabel, accessibilityRole (или новые aria-* и role), достаточный размер области нажатия (hitSlop), поддержка увеличенного шрифта (не ставить фиксированную высоту текстовым блокам).
Частые ошибки
- Текст вне
Text. - Ждать, что
flexDirectionпо умолчаниюrow. ScrollViewс сотнями элементов.Dimensions.getвместо хука при поворотах.- Инлайновые объекты стилей в часто перерисовываемых
memo-компонентах.
Что спросят на собесе
- Чем стили RN отличаются от CSS.
- Умолчания Flexbox в RN.
- Как писать платформенно-зависимый код.
PressableпротивTouchableOpacity.- Как учесть вырезы экрана и клавиатуру.