React Native — это фреймворк от Meta для создания нативных мобильных приложений с помощью JavaScript и React. В отличие от WebView-подходов (Cordova, PhoneGap), React Native компилирует компоненты в настоящие нативные виджеты платформы.
Ключевые идеи:
View, Text, Image и др.В React Native нет <div>, <span> или <p>. Вместо них — нативные аналоги:
| Web (HTML) | React Native | Что делает |
|---|---|---|
| <div> | <View> | Контейнер, flexbox-блок |
| <span>, <p> | <Text> | Любой текст |
| <img> | <Image> | Изображение |
| <input> | <TextInput> | Поле ввода |
| <button> | <TouchableOpacity> | Кнопка с нажатием |
| <ul> | <FlatList> | Прокручиваемый список |
| <div style="overflow:scroll"> | <ScrollView> | Прокручиваемый контейнер |
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
function ProfileCard({ name, role, onPress }) {
return (
<View style={styles.card}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.role}>{role}</Text>
<TouchableOpacity style={styles.button} onPress={onPress}>
<Text style={styles.buttonText}>Подробнее</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
card: {
backgroundColor: '#fff',
borderRadius: 12,
padding: 16,
margin: 8,
// React Native использует flexbox по умолчанию
// и не поддерживает все CSS-свойства
},
name: { fontSize: 18, fontWeight: 'bold', color: '#1a1a1a' },
role: { fontSize: 14, color: '#666', marginTop: 4 },
button: { backgroundColor: '#007AFF', borderRadius: 8, padding: 10, marginTop: 12 },
buttonText: { color: '#fff', textAlign: 'center', fontWeight: '600' },
})CSS в React Native — это объекты JavaScript, а не строки. StyleSheet.create() оптимизирует их и помогает с отладкой:
// Inline стили (не рекомендуется для частых рендеров)
<View style={{ flex: 1, backgroundColor: 'red' }} />
// StyleSheet (оптимизировано)
const styles = StyleSheet.create({
container: {
flex: 1, // занять всё доступное пространство
flexDirection: 'column', // направление по умолчанию — column (не row!)
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#f5f5f5',
}
})
// Несколько стилей
<View style={[styles.container, isActive && styles.active]} />Отличия от CSS:
flexDirection по умолчанию 'column', не 'row'float, нет grid, ограниченный набор свойствimport { Platform, StyleSheet } from 'react-native'
// Способ 1: Platform.OS
const greeting = Platform.OS === 'ios' ? 'Привет, iOS!' : 'Привет, Android!'
// Способ 2: Platform.select()
const styles = StyleSheet.create({
container: {
...Platform.select({
ios: { shadowColor: '#000', shadowOffset: { width: 0, height: 2 } },
android: { elevation: 4 },
}),
borderRadius: 8,
}
})
// Способ 3: файлы с расширением
// Button.ios.tsx — загружается на iOS
// Button.android.tsx — загружается на AndroidExpo (рекомендуется для начала):
npx create-expo-app MyAppBare React Native:
npx react-native init MyAppExpo Managed → Expo Bare → Bare React Native
Проще ←→ Гибче// React Navigation — стандарт навигации
import { NavigationContainer } from '@react-navigation/native'
import { createStackNavigator } from '@react-navigation/stack'
const Stack = createStackNavigator()
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
)
}
// Переход между экранами
function HomeScreen({ navigation }) {
return (
<TouchableOpacity onPress={() => navigation.navigate('Profile', { userId: 42 })}>
<Text>К профилю</Text>
</TouchableOpacity>
)
}Симуляция мобильного дерева компонентов React Native в ванильном JS: фабрики компонентов, StyleSheet-объект и определение платформы
// Симулируем архитектуру React Native на ванильном JS.
// Показываем: компонентные фабрики, StyleSheet, Platform detection.
// --- StyleSheet.create симуляция ---
const StyleSheet = {
create(styles) {
// В реальном RN здесь происходит регистрация стилей
// и оптимизация для нативного слоя
const result = {}
for (const key in styles) {
result[key] = { ...styles[key], __id: Math.random().toString(36).slice(2) }
}
return result
},
flatten(styleArray) {
if (!Array.isArray(styleArray)) return styleArray
return styleArray.filter(Boolean).reduce((acc, style) => ({ ...acc, ...style }), {})
}
}
// --- Platform симуляция ---
const Platform = {
OS: 'ios', // 'ios' | 'android' | 'web'
select(options) {
return options[this.OS] ?? options.default ?? {}
}
}
// --- Базовые компоненты-фабрики ---
function createComponent(type) {
return function(props = {}) {
const { children, style, ...rest } = props
return {
type,
props: rest,
style: StyleSheet.flatten(Array.isArray(style) ? style : [style]),
children: Array.isArray(children) ? children : (children ? [children] : []),
}
}
}
const View = createComponent('View')
const Text = createComponent('Text')
const TouchableOpacity = createComponent('TouchableOpacity')
const Image = createComponent('Image')
// --- Стили (как StyleSheet.create) ---
const styles = StyleSheet.create({
card: {
backgroundColor: '#fff',
borderRadius: 12,
padding: 16,
margin: 8,
...Platform.select({
ios: { shadowColor: '#000', shadowOpacity: 0.1, shadowRadius: 8 },
android: { elevation: 4 },
})
},
title: { fontSize: 18, fontWeight: 'bold', color: '#1a1a1a' },
subtitle: { fontSize: 14, color: '#666', marginTop: 4 },
button: { backgroundColor: '#007AFF', borderRadius: 8, padding: 10, marginTop: 12 },
buttonText: { color: '#fff', textAlign: 'center', fontWeight: '600' },
})
// --- Создание мобильного компонента ---
function ProfileCard(name, role) {
const card = View({
style: styles.card,
children: [
Text({ style: styles.title, children: name }),
Text({ style: styles.subtitle, children: role }),
TouchableOpacity({
style: styles.button,
onPress: () => console.log('Нажато!'),
children: Text({ style: styles.buttonText, children: 'Подробнее' }),
})
]
})
return card
}
// --- Рендер дерева (упрощённо) ---
function renderTree(node, indent = 0) {
const pad = ' '.repeat(indent)
const styleKeys = node.style ? Object.keys(node.style).filter(k => k !== '__id').join(', ') : ''
console.log(pad + '<' + node.type + (styleKeys ? ' style={' + styleKeys + '}' : '') + '>')
if (typeof node.children === 'string' || typeof node.children === 'number') {
console.log(pad + ' ' + node.children)
} else if (Array.isArray(node.children)) {
node.children.forEach(child => {
if (typeof child === 'object' && child !== null) {
renderTree(child, indent + 1)
} else {
console.log(pad + ' ' + child)
}
})
}
console.log(pad + '</' + node.type + '>')
}
// --- Запуск ---
console.log('Платформа:', Platform.OS)
console.log('')
const card = ProfileCard('Алексей Иванов', 'Senior React Native Developer')
console.log('=== Дерево компонентов ===')
renderTree(card)
console.log('')
console.log('=== Стиль карточки ===')
const cardStyleKeys = Object.keys(card.style).filter(k => k !== '__id')
cardStyleKeys.forEach(key => console.log(' ', key + ':', card.style[key]))
console.log('')
console.log('Platform.select результат (iOS):')
console.log(Platform.select({ ios: 'shadowColor', android: 'elevation', default: 'none' }))React Native — это фреймворк от Meta для создания нативных мобильных приложений с помощью JavaScript и React. В отличие от WebView-подходов (Cordova, PhoneGap), React Native компилирует компоненты в настоящие нативные виджеты платформы.
Ключевые идеи:
View, Text, Image и др.В React Native нет <div>, <span> или <p>. Вместо них — нативные аналоги:
| Web (HTML) | React Native | Что делает |
|---|---|---|
| <div> | <View> | Контейнер, flexbox-блок |
| <span>, <p> | <Text> | Любой текст |
| <img> | <Image> | Изображение |
| <input> | <TextInput> | Поле ввода |
| <button> | <TouchableOpacity> | Кнопка с нажатием |
| <ul> | <FlatList> | Прокручиваемый список |
| <div style="overflow:scroll"> | <ScrollView> | Прокручиваемый контейнер |
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
function ProfileCard({ name, role, onPress }) {
return (
<View style={styles.card}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.role}>{role}</Text>
<TouchableOpacity style={styles.button} onPress={onPress}>
<Text style={styles.buttonText}>Подробнее</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
card: {
backgroundColor: '#fff',
borderRadius: 12,
padding: 16,
margin: 8,
// React Native использует flexbox по умолчанию
// и не поддерживает все CSS-свойства
},
name: { fontSize: 18, fontWeight: 'bold', color: '#1a1a1a' },
role: { fontSize: 14, color: '#666', marginTop: 4 },
button: { backgroundColor: '#007AFF', borderRadius: 8, padding: 10, marginTop: 12 },
buttonText: { color: '#fff', textAlign: 'center', fontWeight: '600' },
})CSS в React Native — это объекты JavaScript, а не строки. StyleSheet.create() оптимизирует их и помогает с отладкой:
// Inline стили (не рекомендуется для частых рендеров)
<View style={{ flex: 1, backgroundColor: 'red' }} />
// StyleSheet (оптимизировано)
const styles = StyleSheet.create({
container: {
flex: 1, // занять всё доступное пространство
flexDirection: 'column', // направление по умолчанию — column (не row!)
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#f5f5f5',
}
})
// Несколько стилей
<View style={[styles.container, isActive && styles.active]} />Отличия от CSS:
flexDirection по умолчанию 'column', не 'row'float, нет grid, ограниченный набор свойствimport { Platform, StyleSheet } from 'react-native'
// Способ 1: Platform.OS
const greeting = Platform.OS === 'ios' ? 'Привет, iOS!' : 'Привет, Android!'
// Способ 2: Platform.select()
const styles = StyleSheet.create({
container: {
...Platform.select({
ios: { shadowColor: '#000', shadowOffset: { width: 0, height: 2 } },
android: { elevation: 4 },
}),
borderRadius: 8,
}
})
// Способ 3: файлы с расширением
// Button.ios.tsx — загружается на iOS
// Button.android.tsx — загружается на AndroidExpo (рекомендуется для начала):
npx create-expo-app MyAppBare React Native:
npx react-native init MyAppExpo Managed → Expo Bare → Bare React Native
Проще ←→ Гибче// React Navigation — стандарт навигации
import { NavigationContainer } from '@react-navigation/native'
import { createStackNavigator } from '@react-navigation/stack'
const Stack = createStackNavigator()
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
)
}
// Переход между экранами
function HomeScreen({ navigation }) {
return (
<TouchableOpacity onPress={() => navigation.navigate('Profile', { userId: 42 })}>
<Text>К профилю</Text>
</TouchableOpacity>
)
}Симуляция мобильного дерева компонентов React Native в ванильном JS: фабрики компонентов, StyleSheet-объект и определение платформы
// Симулируем архитектуру React Native на ванильном JS.
// Показываем: компонентные фабрики, StyleSheet, Platform detection.
// --- StyleSheet.create симуляция ---
const StyleSheet = {
create(styles) {
// В реальном RN здесь происходит регистрация стилей
// и оптимизация для нативного слоя
const result = {}
for (const key in styles) {
result[key] = { ...styles[key], __id: Math.random().toString(36).slice(2) }
}
return result
},
flatten(styleArray) {
if (!Array.isArray(styleArray)) return styleArray
return styleArray.filter(Boolean).reduce((acc, style) => ({ ...acc, ...style }), {})
}
}
// --- Platform симуляция ---
const Platform = {
OS: 'ios', // 'ios' | 'android' | 'web'
select(options) {
return options[this.OS] ?? options.default ?? {}
}
}
// --- Базовые компоненты-фабрики ---
function createComponent(type) {
return function(props = {}) {
const { children, style, ...rest } = props
return {
type,
props: rest,
style: StyleSheet.flatten(Array.isArray(style) ? style : [style]),
children: Array.isArray(children) ? children : (children ? [children] : []),
}
}
}
const View = createComponent('View')
const Text = createComponent('Text')
const TouchableOpacity = createComponent('TouchableOpacity')
const Image = createComponent('Image')
// --- Стили (как StyleSheet.create) ---
const styles = StyleSheet.create({
card: {
backgroundColor: '#fff',
borderRadius: 12,
padding: 16,
margin: 8,
...Platform.select({
ios: { shadowColor: '#000', shadowOpacity: 0.1, shadowRadius: 8 },
android: { elevation: 4 },
})
},
title: { fontSize: 18, fontWeight: 'bold', color: '#1a1a1a' },
subtitle: { fontSize: 14, color: '#666', marginTop: 4 },
button: { backgroundColor: '#007AFF', borderRadius: 8, padding: 10, marginTop: 12 },
buttonText: { color: '#fff', textAlign: 'center', fontWeight: '600' },
})
// --- Создание мобильного компонента ---
function ProfileCard(name, role) {
const card = View({
style: styles.card,
children: [
Text({ style: styles.title, children: name }),
Text({ style: styles.subtitle, children: role }),
TouchableOpacity({
style: styles.button,
onPress: () => console.log('Нажато!'),
children: Text({ style: styles.buttonText, children: 'Подробнее' }),
})
]
})
return card
}
// --- Рендер дерева (упрощённо) ---
function renderTree(node, indent = 0) {
const pad = ' '.repeat(indent)
const styleKeys = node.style ? Object.keys(node.style).filter(k => k !== '__id').join(', ') : ''
console.log(pad + '<' + node.type + (styleKeys ? ' style={' + styleKeys + '}' : '') + '>')
if (typeof node.children === 'string' || typeof node.children === 'number') {
console.log(pad + ' ' + node.children)
} else if (Array.isArray(node.children)) {
node.children.forEach(child => {
if (typeof child === 'object' && child !== null) {
renderTree(child, indent + 1)
} else {
console.log(pad + ' ' + child)
}
})
}
console.log(pad + '</' + node.type + '>')
}
// --- Запуск ---
console.log('Платформа:', Platform.OS)
console.log('')
const card = ProfileCard('Алексей Иванов', 'Senior React Native Developer')
console.log('=== Дерево компонентов ===')
renderTree(card)
console.log('')
console.log('=== Стиль карточки ===')
const cardStyleKeys = Object.keys(card.style).filter(k => k !== '__id')
cardStyleKeys.forEach(key => console.log(' ', key + ':', card.style[key]))
console.log('')
console.log('Platform.select результат (iOS):')
console.log(Platform.select({ ios: 'shadowColor', android: 'elevation', default: 'none' }))Создай React-компонент ProfileCard, который демонстрирует структуру React Native компонентов. Компонент принимает пропсы name, role и onPress. Используй симуляцию нативных компонентов: View как контейнер с flexbox, Text для текста, TouchableOpacity для кнопки. Стили задаются через объект styles (как StyleSheet.create в React Native).
ProfileCard должен использовать View с styles.card, два Text для name (styles.name) и role (styles.role), и TouchableOpacity с onPress для кнопки. Внутри кнопки — Text со стилем buttonText.