React Native 完整开发教程与实战指南

Viewed 0

项目初始化

创建新应用

如果之前安装了全局的 react-native-cli 包,请先将其卸载,以避免潜在问题:

npm uninstall -g react-native-cli @react-native-community/cli

接下来,使用 React Native Community CLI 生成一个新项目。例如,创建一个名为 "MyApp" 的项目:

npx @react-native-community/cli@latest init MyApp

如果你是在现有应用中集成 React Native,或项目中已安装 Expo,则不需要此步骤。也可以使用第三方 CLI 来设置 React Native 应用。

在初始化安装阶段,请勿中断过程。如果在 iOS 上遇到问题,可以尝试通过以下步骤重新安装依赖项:

cd ios
bundle install
bundle exec pod install

若希望使用特定 React Native 版本创建项目,可以使用 --version 参数:

npx @react-native-community/cli@X.XX.X init MyApp --version X.XX.X

此外,--template 参数可用于基于自定义模板启动项目。

启动 Metro

Metro 是 React Native 的 JavaScript 构建工具。要启动 Metro 开发服务器,请在项目文件夹中运行:

yarn start

Metro 类似于 Web 开发中的 Vite 或 webpack,但专为 React Native 设计,例如使用 Babel 转换 JSX 等语法。

启动应用程序

保持 Metro Bundler 在独立终端中运行,然后在项目文件夹中打开新终端并执行:

yarn android

如果设置正确,应用将很快在 Android 模拟器中运行。你也可以直接通过 Android Studio 启动应用。

工程化说明

创建项目后,建议优化目录结构如下:

MyApp/
├── android/           # Android 原生代码
├── ios/               # iOS 原生代码
├── node_modules/      # npm 依赖包
├── src/               # 应用源代码
│   ├── components/    # 可复用组件
│   ├── screens/       # 页面组件
│   ├── navigation/    # 路由导航
│   ├── assets/        # 静态资源(图片、字体等)
│   ├── services/      # 网络请求或其他服务
│   └── utils/         # 工具函数
├── App.js            # 应用主入口
├── package.json      # npm 配置文件
├── babel.config.js   # Babel 配置
├── metro.config.js   # Metro bundler 配置
└── index.js          # React Native 入口文件

重要文件与目录包括:

  • android/ios/:包含各自平台的原生代码和配置,可用于修改平台特性或添加依赖。
  • src/:应用的主要源代码目录,推荐将所有逻辑和组件组织于此。
    • components/:存放可复用的 UI 组件。
    • screens/:应用的各个页面组件。
    • navigation/:处理路由和导航逻辑,通常使用库如 @react-navigation/native。
    • assets/:存放图片、字体等静态资源。
    • services/:处理网络请求或 API 调用。
    • utils/:存放通用工具函数,如日期格式化或字符串处理。
  • App.js:应用的主组件和入口点。
  • package.json:定义项目依赖和脚本。
  • babel.config.js:Babel 配置文件,用于代码转译。
  • metro.config.js:Metro bundler 的配置文件,可自定义打包行为。
  • index.js:React Native 应用的入口文件,用于注册主组件。

项目配置方面,可以使用 npm 或 yarn 管理依赖,在 iOS 和 Android 文件夹内配置环境设置(如 API 地址),并使用 StyleSheet 或样式库(如 styled-components)管理样式。

关于 Expo 框架

Expo 可以简化开发,但会引入额外学习成本。对于初学者,建议直接使用原生 React Native 进行开发,以便更深入地学习。Expo 的 GitHub 链接可供参考。

常用组件与 API

常用组件

React Native 提供了多种内置组件用于快速构建用户界面。

View:最基本组件,用于构建 UI 布局,可容纳其他组件并支持样式和事件处理。它类似于 Web 中的 div。

import { View } from 'react-native';
const MyComponent = () => {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      {/* 其他组件 */}
    </View>
  );
};

Text:用于显示文本,支持多种样式如字体、颜色和大小。

import { Text } from 'react-native';
const MyText = () => {
  return <Text style={{ fontSize: 20, color: 'blue' }}>Hello, React Native!</Text>;
};

Image:用于显示图片,支持本地和网络图片源。

import { Image } from 'react-native';
const MyImage = () => {
  return <Image source={{ uri: 'https://example.com/image.png' }} style={{ width: 100, height: 100 }} />;
};

ScrollView:创建可滚动视图,适用于内容较多的场景。

import { ScrollView, Text } from 'react-native';
const MyScrollView = () => {
  return (
    <ScrollView>
      <Text>Item 1</Text>
      <Text>Item 2</Text>
      <Text>Item 3</Text>
    </ScrollView>
  );
};

TextInput:接收用户输入,可设置占位符和样式。

import { TextInput } from 'react-native';
const MyTextInput = () => {
  return <TextInput style={{ height: 40, borderColor: 'gray', borderWidth: 1 }} placeholder="Type here" />;
};

Button:创建按钮并支持点击事件。

import { Button } from 'react-native';
const MyButton = () => {
  return <Button title="Click Me" onPress={() => alert('Button pressed!')} />;
};

FlatList:高效渲染长列表,支持性能优化。

import { FlatList, Text } from 'react-native';
const DATA = [
  { id: '1', title: 'Item 1' },
  { id: '2', title: 'Item 2' },
  { id: '3', title: 'Item 3' },
];
const MyFlatList = () => {
  return <FlatList data={DATA} renderItem={({ item }) => <Text>{item.title}</Text>} keyExtractor={item => item.id} />;
};

TouchableOpacity:实现可点击元素,支持透明度变化反馈。

import { TouchableOpacity, Text } from 'react-native';
const MyTouchable = () => {
  return (
    <TouchableOpacity onPress={() => alert('Tapped!')}>
      <Text style={{ fontSize: 20 }}>Tap Me</Text>
    </TouchableOpacity>
  );
};

Modal:创建模态窗口,适用于对话框等需要用户注意的场景。

import { Modal, View, Text, Button } from 'react-native';
const MyModal = () => {
  const [modalVisible, setModalVisible] = useState(false);
  return (
    <View>
      <Button title="Show Modal" onPress={() => setModalVisible(true)} />
      <Modal transparent={true} visible={modalVisible} animationType="slide">
        <View style={{ marginTop: 50 }}>
          <Text>This is a Modal!</Text>
          <Button title="Hide Modal" onPress={() => setModalVisible(false)} />
        </View>
      </Modal>
    </View>
  );
};

SafeAreaView:确保内容显示在设备安全区域内,常用于处理刘海屏等特殊屏幕。

<SafeAreaView style={backgroundStyle}>
  <StatusBar />
</SafeAreaView>

样式表

在 React Native 中,样式管理通过 StyleSheet API 实现,它允许创建样式对象并直接应用到组件,提高可读性和性能。

import { StyleSheet, View, Text } from 'react-native';
const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#f5fcff' },
  text: { fontSize: 20, color: 'blue' },
});
const MyComponent = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Hello, React Native!</Text>
    </View>
  );
};

StyleSheet.create 方法在内部优化样式,避免每次渲染时重新计算。

主题实现可以通过 React Context API 动态切换样式。例如,创建主题上下文:

import React, { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');
  const toggleTheme = () => setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
  return <ThemeContext.Provider value={{ theme, toggleTheme }}>{children}</ThemeContext.Provider>;
};
const useTheme = () => useContext(ThemeContext);

在组件中使用主题:

const ThemedComponent = () => {
  const { theme } = useTheme();
  const styles = StyleSheet.create({
    container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: theme === 'light' ? '#fff' : '#333' },
    text: { color: theme === 'light' ? '#000' : '#fff' },
  });
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Current Theme: {theme}</Text>
    </View>
  );
};

StyleSheet 的原理涉及将 JavaScript 样式对象映射到原生代码,通过缓存和优化属性(如 flex、padding)来提高性能。样式合并可通过 StyleSheet.flatten 处理,而跨平台支持则使用 Platform 模块:

import { Platform, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
  button: { backgroundColor: Platform.OS === 'ios' ? 'blue' : 'green', padding: 10 },
});

路由处理

React Navigation 是常用的路由库,通过 @react-navigation 系列包管理导航。例如,安装依赖后,可以创建底部标签导航和堆栈导航。

首先,创建底部标签导航:

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
const TabBar = createBottomTabNavigator();
function BottomBar() {
  return (
    <TabBar.Navigator screenOptions={{ headerShown: false }}>
      <TabBar.Screen name="TabHome" component={HomeScreen} options={{ tabBarLabel: '首页' }} />
      <TabBar.Screen name="TabOther" component={DetailScreen} options={{ tabBarLabel: '其他' }} />
    </TabBar.Navigator>
  );
}

然后,创建堆栈导航作为根导航器:

import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { NavigationContainer } from '@react-navigation/native';
const Stack = createNativeStackNavigator();
function Navigator() {
  return (
    <NavigationContainer>
      <Stack.Navigator
        screenOptions={{
          headerTitleAlign: 'center',
          headerBackTitleVisible: false,
          gestureEnabled: true,
          gestureDirection: 'horizontal',
          headerStyle: { backgroundColor: Colors.primary },
        }}>
        <Stack.Screen name="BottomBar" component={BottomBar} />
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailScreen} />
        <Stack.Screen name="Topics" component={TopicsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

导航状态由 React Navigation 自动管理,用户可以通过 navigation.navigate 方法在屏幕间切换。对于 iOS,可能需要执行 npx pod-install ios 或进入 ios 文件夹运行 pod install 来安装原生依赖。

常用 API

AsyncStorage:用于本地存储简单数据。

import AsyncStorage from '@react-native-async-storage/async-storage';
const storeData = async value => {
  try { await AsyncStorage.setItem('@storage_Key', value); } catch (e) {}
};
const getData = async () => {
  try {
    const value = await AsyncStorage.getItem('@storage_Key');
    if (value !== null) { /* 处理数据 */ }
  } catch (e) {}
};

Fetch API:进行网络请求。

const fetchData = async () => {
  try {
    let response = await fetch('https://api.example.com/data');
    let json = await response.json();
    console.log(json);
  } catch (error) { console.error(error); }
};

Linking:处理外部链接,如打开网页或拨打电话。

import { Linking } from 'react-native';
const openURL = async url => {
  const supported = await Linking.canOpenURL(url);
  if (supported) await Linking.openURL(url);
};
const makeCall = phoneNumber => Linking.openURL(`tel:${phoneNumber}`);

DeviceInfo:获取设备信息,需安装 react-native-device-info。

import DeviceInfo from 'react-native-device-info';
const getDeviceInfo = async () => {
  const deviceId = await DeviceInfo.getDeviceId();
  const systemVersion = await DeviceInfo.getSystemVersion();
  console.log(`Device ID: ${deviceId}, System Version: ${systemVersion}`);
};

Permissions:请求和检查设备权限,需安装 react-native-permissions。

import { PermissionsAndroid } from 'react-native';
const requestLocationPermission = async () => {
  try {
    const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, {
      title: '位置权限',
      message: '需要访问您的位置',
      buttonNeutral: '稍后询问',
      buttonNegative: '取消',
      buttonPositive: '确认',
    });
    if (granted === PermissionsAndroid.RESULTS.GRANTED) console.log('您可以使用位置');
    else console.log('位置权限被拒绝');
  } catch (err) { console.warn(err); }
};

Vibration:控制设备震动。

import { Vibration } from 'react-native';
const triggerVibration = () => Vibration.vibrate(1000);

Share:分享内容到其他应用。

import { Share } from 'react-native';
const shareMessage = async () => {
  try {
    const result = await Share.share({ message: '这是要分享的消息' });
    if (result.action === Share.sharedAction) { /* 分享成功 */ }
    else if (result.action === Share.dismissedAction) { /* 分享取消 */ }
  } catch (error) { alert(error.message); }
};

StatusBar:控制状态栏样式和行为。

import { StatusBar } from 'react-native';
const setStatusBar = () => {
  StatusBar.setBarStyle('light-content', true);
  StatusBar.setBackgroundColor('#000000');
};

多端开发方案

React Native 支持跨平台开发,通过 Platform API 实现 iOS 和 Android 之间的适配。Platform.OS 可用于条件渲染,而 Platform.select 允许为不同平台定义样式或值。

import { Platform, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
  container: {
    flex: 1,
    ...Platform.select({ android: { backgroundColor: 'green' }, ios: { backgroundColor: 'red' }, default: { backgroundColor: 'blue' } }),
  },
});

平台常量如 Platform.isPad 可用于设备特定逻辑。图片资源也可按平台选择:

const imageSource = Platform.select({
  ios: require('./images/image_ios.png'),
  android: require('./images/image_android.png'),
});

第三方库如 react-native-elements 或 react-native-paper 提供跨平台 UI 组件。性能和体验优化需考虑平台特性,例如 Android 的返回按钮行为可能与 iOS 导航模式不同,需在逻辑中适配。

原生模块开发与接入

当应用需要平台特有功能时,可通过原生模块连接 JavaScript 与原生代码。新架构引入 Turbo Native Module 和 Fabric Native Components 替代旧版 NativeModules。

以实现 Web Storage API 的 localStorage 为例,使用 Android 的 SharedPreferences 和 iOS 的 NSUserDefaults。

原生模块开发与接入 (iOS)

首先,创建规范文件 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') as Spec;

配置 package.json 的 codegenConfig 后,运行 Codegen 生成平台代码。然后,在 iOS 项目中实现模块。

创建 RCTNativeLocalStorage 类,实现生成的接口:

#import "RCTNativeLocalStorage.h"
static NSString *const RCTNativeLocalStorageKey = @"local-storage";
@interface RCTNativeLocalStorage()
@property (strong, nonatomic) NSUserDefaults *localStorage;
@end
@implementation RCTNativeLocalStorage
RCT_EXPORT_MODULE(NativeLocalStorage)
- (id)init {
  if (self = [super init]) { _localStorage = [[NSUserDefaults alloc] initWithSuiteName:RCTNativeLocalStorageKey]; }
  return self;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
  return std::make_shared<facebook::react::NativeLocalStorageSpecJSI>(params);
}
- (NSString * _Nullable)getItem:(NSString *)key { return [self.localStorage stringForKey:key]; }
- (void)setItem:(NSString *)value key:(NSString *)key { [self.localStorage setObject:value forKey:key]; }
- (void)removeItem:(NSString *)key { [self.localStorage removeObjectForKey:key]; }
- (void)clear {
  NSDictionary *keys = [self.localStorage dictionaryRepresentation];
  for (NSString *key in keys) { [self removeItem:key]; }
}
@end

在 JavaScript 中使用该模块:

import NativeLocalStorage from './specs/NativeLocalStorage';
const storedValue = NativeLocalStorage?.getItem('myKey');
NativeLocalStorage?.setItem('newValue', 'myKey');

原生模块开发与接入 (Android)

在 Android 端,创建 NativeLocalStorageModule 实现接口:

package com.nativelocalstorage;
import android.content.Context;
import android.content.SharedPreferences;
import com.facebook.react.bridge.ReactApplicationContext;
public class NativeLocalStorageModule extends NativeLocalStorageSpec {
  private static final String NAME = "NativeLocalStorage";
  public NativeLocalStorageModule(ReactApplicationContext reactContext) { super(reactContext); }
  @Override public String getName() { return NAME; }
  @Override public void setItem(String value, String key) {
    SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPref.edit();
    editor.putString(key, value);
    editor.apply();
  }
  @Override public String getItem(String key) {
    SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
    return sharedPref.getString(key, null);
  }
  @Override public void removeItem(String key) {
    SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
    sharedPref.edit().remove(key).apply();
  }
  @Override public void clear() {
    SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);
    sharedPref.edit().clear().apply();
  }
}

创建 NativeLocalStoragePackage 注册模块:

package com.nativelocalstorage;
import com.facebook.react.TurboReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import java.util.HashMap;
import java.util.Map;
public class NativeLocalStoragePackage extends TurboReactPackage {
  @Override
  public NativeModule getModule(String name, ReactApplicationContext reactContext) {
    if (name.equals(NativeLocalStorageModule.NAME)) return new NativeLocalStorageModule(reactContext);
    else return null;
  }
  @Override
  public ReactModuleInfoProvider getReactModuleInfoProvider() {
    return () -> {
      Map<String, ReactModuleInfo> map = new HashMap<>();
      map.put(NativeLocalStorageModule.NAME, new ReactModuleInfo(NativeLocalStorageModule.NAME, NativeLocalStorageModule.NAME, false, false, false, true));
      return map;
    };
  }
}

在 MainApplication 中添加该包:

package com.turbomoduleexample;
import com.facebook.react.PackageList;
import com.facebook.react.ReactPackage;
import com.nativelocalstorage.NativeLocalStoragePackage;
public class MainApplication extends Application implements ReactApplication {
  private final ReactNativeHost reactNativeHost = new DefaultReactNativeHost(this) {
    @Override public List<ReactPackage> getPackages() {
      List<ReactPackage> packages = new PackageList(this).getPackages();
      packages.add(new NativeLocalStoragePackage());
      return packages;
    }
  };
}

应用构建发布

构建和发布涉及 iOS 和 Android 平台的配置、图标、打包和发布步骤。

应用信息配置

  • iOS:在 Xcode 中配置应用名称、版本、构建号和 Bundle Identifier,修改 Info.plist 文件。启动页通过 LaunchScreen 设置。
  • Android:在 AndroidManifest.xml 中配置应用名称和图标,在 build.gradle 中设置版本和包名。

图标配置

图标可通过在线工具一键生成。iOS 图标添加到 Xcode 的 Assets.xcassets,Android 图标放置于 android/app/src/main/res 的相应 mipmap 文件夹中。

打包

  • iOS:使用 Xcode 选择 Product > Archive 进行打包,然后通过 Distribute App 导出。
  • Android:在项目根目录运行 cd android && ./gradlew assembleRelease,APK 文件生成于 android/app/build/outputs/apk/release。

发布

  • iOS:通过 App Store Connect 创建应用条目,使用 Xcode 或 Transporter 上传 .ipa 文件,提交审核。
  • Android:在 Google Play Console 创建应用,上传 APK 文件并填写描述等信息,提交审核。

补充资料

  • React Native 官方文档
  • React Navigation 文档
  • React Native 样式表文档
  • Material Design UI 库:React Native Paper
  • 基于 Tailwind 的 UI 库:Gluestack
  • 小清新 UI 库:Tamagui
  • 构建分发平台
  • 苹果发布平台:App Store Connect
  • 老架构原生模块开发文档
  • 新架构原生模块开发文档
  • Turbo Native Module 架构文档
  • Fabric Native Components 架构文档
  • React Native 新架构概述
  • Hermes JavaScript 引擎
0 Answers