React Native - 开始
# 资料
# 组件
# 原生组件
在 Android 开发中,视图通常使用 Kotlin 或 Java 编写;在 iOS 开发中,则使用 Swift 或 Objective-C。而使用 React Native,你可以利用 React 组件通过 JavaScript 调用这些视图。在运行时,React Native 会为这些组件创建相应的 Android 和 iOS 视图。由于 React Native 组件与 Android 和 iOS 组件使用相同的视图,因此 React Native 应用的外观、体验和性能与其他应用并无二致。我们将这些平台支持的组件称为原生组件。
# 核心组件
| React Native UI 组件 | Android 原生视图 | iOS 原生视图 | Web 标签 |
|---|---|---|---|
<View> | <ViewGroup> | <UIView> | A non-scrolling <div> |
<Text> | <TextView> | <UITextView> | <p> |
<Image> | <ImageView> | <UIImageView> | <img> |
<ScrollView> | <ScrollView> | <UIScrollView> | <div> |
<TextInput> | <EditText> | <UITextField> | <input type="text"> |
# 特定平台代码
参考:Introduction · React Native (opens new window) React Native 提供了两种方法来区分平台:
- 使用 Platform 模块.
- 使用特定平台后缀.
# Platform 模块
import {Platform, StyleSheet} from 'react-native';
const styles = StyleSheet.create({
// `Platform.OS`在 iOS 上会返回`ios`,而在 Android 设备或模拟器上则会返回`android`
height: Platform.OS === 'ios' ? 200 : 100,
});
Platform.select() :
import {Platform, StyleSheet} from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
...Platform.select({
ios: {
backgroundColor: 'red',
},
android: {
backgroundColor: 'green',
},
default: {
// other platforms, web for example
backgroundColor: 'blue',
},
}),
},
});
# 特定平台后缀
BigButton.ios.js
BigButton.android.js
# 环境搭建
# 原生开发
因为某种原因,必须调用原生平台代码执行。
- Native Modules:原生模块,指的是那些没有为用户提供用户界面的原生库。例如,用于存储数据、发送通知、处理网络事件的模块。这些模块可以作为函数或对象被 JavaScript 应用程序代码所调用。
- Native Component:原生组件,通过 React 组件,应用程序的 JavaScript 代码可以调用原生平台的视图、小部件和控制器。
# Native Modules 原生模块
以调用 Android 和 iOS 接口实现原生持久存储能力:
# TS 接口
- 根目录创建
specs文件夹 - 下创建
NativeLocalStorage.ts文件,如需其他名字应以Native为前缀
specs/NativeLocalStorage.ts
import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {
setItem(value: string, key: string): void;
getItem(key: string): string | null;
removeItem(key: string): void;
clear(): void;
}
export default TurboModuleRegistry.getEnforcing<Spec>(
'NativeLocalStorage',
);
# 配置
"codegenConfig": {
"name": "NativeLocalStorageSpec",
"type": "modules",
"jsSrcsDir": "specs",
"android": {
"javaPackageName": "com.nativelocalstorage"
}
},
# 生成原生接口代码
在构建 Android 应用程序时,该过程会自动执行,无需手动操作。
cd android
./gradlew generateCodegenArtifactsFromSchema
# TS 调用原生方法
// 如果 Turbo Native Module 不可用,该操作将返回 `null`
get<T>(name: string): T | null
// 如果 Turbo Native Module 不可用,就会抛出异常。该代码假设该模块始终可用。
getEnforcing<T>(name: string): T
import {useEffect, useState, type JSX} from 'react';
import {
SafeAreaView,
StyleSheet,
Text,
TextInput,
Button,
} from 'react-native';
import NativeLocalStorage from './specs/NativeLocalStorage';
const EMPTY = '<empty>';
function App(): JSX.Element {
const [value, setValue] = useState<string | null>(null);
const [editingValue, setEditingValue] = useState<string | null>(
null,
);
useEffect(() => {
const storedValue = NativeLocalStorage?.getItem('myKey');
setValue(storedValue ?? '');
}, []);
function saveValue() {
NativeLocalStorage?.setItem(editingValue ?? EMPTY, 'myKey');
setValue(editingValue);
}
function clearAll() {
NativeLocalStorage?.clear();
setValue('');
}
function deleteValue() {
NativeLocalStorage?.removeItem('myKey');
setValue('');
}
return (
<SafeAreaView style={{flex: 1}}>
<Text style={styles.text}>
Current stored value is: {value ?? 'No Value'}
</Text>
<TextInput
placeholder="Enter the text you want to store"
style={styles.textInput}
onChangeText={setEditingValue}
/>
<Button title="Save" onPress={saveValue} />
<Button title="Delete" onPress={deleteValue} />
<Button title="Clear" onPress={clearAll} />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
text: {
margin: 10,
fontSize: 20,
},
textInput: {
margin: 10,
height: 40,
borderColor: 'black',
borderWidth: 1,
paddingLeft: 5,
paddingRight: 5,
borderRadius: 5,
},
});
export default App;
# 编写对应平台代码
# Android
package com.nativelocalstorage
import android.content.Context
import android.content.SharedPreferences
import com.nativelocalstorage.NativeLocalStorageSpec
import com.facebook.react.bridge.ReactApplicationContext
class NativeLocalStorageModule(reactContext: ReactApplicationContext) : NativeLocalStorageSpec(reactContext) {
override fun getName() = NAME
override fun setItem(value: String, key: String) {
val sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
val editor = sharedPref.edit()
editor.putString(key, value)
editor.apply()
}
override fun getItem(key: String): String? {
val sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
val username = sharedPref.getString(key, null)
return username.toString()
}
override fun removeItem(key: String) {
val sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
val editor = sharedPref.edit()
editor.remove(key)
editor.apply()
}
override fun clear() {
val sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
val editor = sharedPref.edit()
editor.clear()
editor.apply()
}
companion object {
const val NAME = "NativeLocalStorage"
}
}
# Native Modules 原生模块 (旧)
以创建一个 Calendar 原生模块为例
# 创建自定义原生模块文件
- 使用 Android Studio 打开 rn 项目下的
android - 创建目录:
android/app/src/main/java/com/your-app-name/ - 目录下创建:
CalendarModule.kt
package com.your-apps-package-name; // replace your-apps-package-name with your app’s package name
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
class CalendarModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {...}
继承 ReactContextBaseJavaModule 类,使 React Native 视为原生模块
# 重写 getName () 定义原生模块名称
// add to CalendarModule.kt
override fun getName() = "CalendarModule"
# 导出原生方法
通过 @ReactMethod 注解声明 JS 可调用的原生方法
import android.util.Log
@ReactMethod
fun createCalendarEvent(name: String, location: String) {
Log.d("CalendarModule", "Create event called with name: $name and location: $location")
}
同步方法
- 在
@ReactMethod注解中添加配置isBlockingSynchronousMethod = true - 不建议这么做,因为以同步的方式调用方法可能会带来严重的性能损失,并且可能会给你的原生模块引入与线程相关的 bug。
@ReactMethod(isBlockingSynchronousMethod = true)
# 注册模块
- 创建目录:
android/app/src/main/java/com/your-app-name/ - 目录下创建:
MyAppPackage.kt,实现ReactPackage接口 - 在
createNativeModules()函数,添加实例化的CalendarModule到NativeModules
package com.your-app-name // replace your-app-name with your app’s name
import android.view.View
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager
class MyAppPackage : ReactPackage {
override fun createViewManagers(
reactContext: ReactApplicationContext
): MutableList<ViewManager<View, ReactShadowNode<*>>> = mutableListOf()
override fun createNativeModules(
reactContext: ReactApplicationContext
): MutableList<NativeModule> = listOf(CalendarModule(reactContext)).toMutableList()
}
Note
值得注意的是,这种注册原生模块的方式会在应用启动时主动地初始化所有原生模块,从而增加了应用的启动时间。
上次更新: 2026/08/20, 18:03:47