JavaScript基础课程三十一、React Native 跨端 App 入门

JavaScript基础课程三十一、React Native 跨端 App 入门 JavaScript 前端核心进阶React Native 跨端 App 课程本课是前端开发者迈向原生App开发的关键一课聚焦React Native跨端框架入门依托已学的React知识实现从Web开发到原生App开发的平滑过渡。RN凭借原生渲染的性能优势、React语法的低门槛成为前端开发者开发高性能跨端App的首选方案。课程从环境搭建、核心组件、样式系统到路由导航、列表渲染、交互逻辑用单词App案例贯穿全程拆解跨端开发的核心逻辑与避坑要点。掌握本课内容你将具备双端原生App的独立开发能力打破前端与客户端的技术壁垒拓宽技术边界与就业方向。RN与React的语法高度统一学习成本极低是前端开发者拓展技术栈的最优选择之一。一、课程学习目的理解 React Native简称RN的核心定位、底层原理掌握“一套代码双端运行”的跨端开发逻辑。完成RN开发环境搭建学会使用Expo快速启动项目降低原生环境配置门槛。掌握RN核心组件、样式系统、布局规则衔接已学的React知识实现从Web到原生App的平滑过渡。学会使用React Navigation实现App页面路由、跳转与参数传递搭建多页面App结构。掌握RN列表渲染、用户交互、调试方法规避跨端开发常见坑。独立开发可运行在iOS/Android双端的简易App建立原生App开发思维为企业级跨端项目开发奠定基础。二、核心知识点讲解1. React Native 基础认知React Native 是Meta原Facebook推出的跨平台原生App开发框架基于React语法一套代码可同时编译为iOS、Android双端原生应用。核心优势原生渲染非WebView套壳代码通过JS桥接渲染为原生组件性能接近原生App语法复用完全兼容React Hooks、组件化开发模式前端开发者上手成本极低热更新支持热重载修改代码实时预览无需重新编译原生包生态完善拥有丰富的第三方原生插件覆盖绝大多数App开发场景与uni-app的核心差异RN主打原生渲染性能适合中大型高性能Appuni-app主打多端全覆盖小程序/H5/App适合轻量化全平台项目。2. 开发环境搭建RN开发分为原生环境和Expo快速开发环境入门阶段优先使用Expo无需配置Android Studio/Xcode开箱即用。必备环境Node.js18.0及以上版本手机端安装「Expo Go」App用于真机预览代码编辑器VS Code推荐安装React Native相关插件采用项目创建命令# 全局安装Expo脚手架 npm install -g create-expo-app # 创建RN项目 npx create-expo-app rn-word-app # 进入项目启动开发服务 cd rn-word-app npm start3. RN 核心组件替代HTML标签RN无HTML标签所有视图均使用官方提供的原生组件核心常用组件如下RN组件对应Web标签核心作用Viewdiv视图容器用于布局、包裹子元素Textspan/p文本展示所有文字必须放在Text组件内Imageimg图片展示支持本地与网络图片TextInputinput输入框处理用户文本输入Buttonbutton按钮组件处理点击交互ScrollViewdiv(overflow:scroll)滚动容器用于少量内容滚动FlatListul/li 虚拟列表长列表渲染自带复用优化适合长列表场景4. RN 样式系统与布局规则RN样式完全基于JavaScript编写无CSS文件使用StyleSheet.create统一管理样式核心规则布局默认使用Flex弹性布局默认主轴为垂直方向flexDirection: column与Web默认水平方向相反无单位样式数值为无单位的密度无关像素自动适配不同屏幕密度样式无继承除Text组件外父组件样式不会传递给子组件仅支持Web CSS的子集无后代选择器、伪类、浮动等特性5. 路由与页面跳转RN官方无内置路由主流使用React Navigation库实现页面导航核心分为栈导航Stack Navigation、标签导航Tab Navigation。栈导航实现页面的推入、弹出、返回类似小程序的navigateTo/navigateBack标签导航实现底部TabBar切换对应小程序的tabBar配置6. 生命周期与HooksRN完全兼容React的所有HooksuseState、useEffect、useCallback等均可直接使用生命周期逻辑与React完全一致无需额外学习成本。三、示例程序带详细注释示例1基础页面与样式单词首页// App.js 项目入口文件 import { StyleSheet, Text, View, Button } from react-native; import { NavigationContainer } from react-navigation/native; import { createNativeStackNavigator } from react-navigation/native-stack; import WordList from ./src/pages/WordList; import WordDetail from ./src/pages/WordDetail; // 创建栈导航 const Stack createNativeStackNavigator(); export default function App() { return ( // 导航容器必须包裹所有路由 NavigationContainer Stack.Navigator initialRouteNameHome {/* 首页路由 */} Stack.Screen nameHome component{HomeScreen} options{{ title: 单词学习App }} / {/* 单词列表页 */} Stack.Screen nameWordList component{WordList} options{{ title: 单词列表 }} / {/* 单词详情页 */} Stack.Screen nameWordDetail component{WordDetail} options{{ title: 单词详情 }} / /Stack.Navigator /NavigationContainer ); } // 首页组件 function HomeScreen({ navigation }) { return ( View style{styles.container} Text style{styles.title}欢迎使用单词学习App/Text Text style{styles.desc}基于React Native开发的跨端单词工具/Text {/* 跳转到单词列表页 */} Button title进入单词列表 onPress{() navigation.navigate(WordList)} / /View ); } // 样式定义 const styles StyleSheet.create({ container: { flex: 1, // 占满全屏 backgroundColor: #f5f5f5, alignItems: center, // 水平居中 justifyContent: center, // 垂直居中 padding: 20, }, title: { fontSize: 24, fontWeight: bold, color: #333, marginBottom: 12, }, desc: { fontSize: 16, color: #666, marginBottom: 30, }, });示例2单词列表页FlatList长列表渲染// src/pages/WordList.js import { StyleSheet, View, Text, FlatList, Pressable } from react-native; import { useEffect, useState } from react; export default function WordList({ navigation }) { // 响应式单词数据 const [wordList, setWordList] useState([]); // 模拟请求数据useEffect用法与React完全一致 useEffect(() { const mockData [ { id: 1, en: apple, cn: 苹果, phonetic: /ˈæpl/ }, { id: 2, en: banana, cn: 香蕉, phonetic: /bəˈnɑːnə/ }, { id: 3, en: orange, cn: 橙子, phonetic: /ˈɒrɪndʒ/ }, { id: 4, en: react, cn: 前端框架, phonetic: /riˈækt/ }, { id: 5, en: native, cn: 原生的, phonetic: /ˈneɪtɪv/ }, ]; setWordList(mockData); }, []); // 列表项渲染 const renderItem ({ item }) ( Pressable style{styles.item} // 跳转到详情页传递单词参数 onPress{() navigation.navigate(WordDetail, { word: item })} Text style{styles.en}{item.en}/Text Text style{styles.cn}{item.cn}/Text /Pressable ); return ( View style{styles.container} FlatList data{wordList} renderItem{renderItem} keyExtractor{item item.id} // 唯一key对应小程序的wx:key / /View ); } const styles StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: #fff, }, item: { padding: 16, borderBottomWidth: 1, borderBottomColor: #eee, flexDirection: row, justifyContent: space-between, }, en: { fontSize: 18, fontWeight: 500, color: #333, }, cn: { fontSize: 16, color: #666, }, });示例3单词详情页路由参数接收// src/pages/WordDetail.js import { StyleSheet, View, Text } from react-native; export default function WordDetail({ route }) { // 接收路由传递的单词参数 const { word } route.params; return ( View style{styles.container} View style{styles.card} Text style{styles.en}{word.en}/Text Text style{styles.phonetic}{word.phonetic}/Text Text style{styles.cn}{word.cn}/Text /View /View ); } const styles StyleSheet.create({ container: { flex: 1, padding: 20, backgroundColor: #f5f5f5, }, card: { backgroundColor: #fff, padding: 30, borderRadius: 12, alignItems: center, shadowColor: #000, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, }, en: { fontSize: 32, fontWeight: bold, color: #333, marginBottom: 8, }, phonetic: { fontSize: 18, color: #666, marginBottom: 16, }, cn: { fontSize: 24, color: #42b983, }, });示例4路由依赖安装命令# 安装React Navigation核心依赖 npm install react-navigation/native npm install react-navigation/native-stack # Expo环境安装配套依赖 npx expo install react-native-screens react-native-safe-area-context四、掌握技巧与方法入门优先使用Expo环境无需配置复杂的原生开发环境快速验证代码效果。牢记Flex布局主轴差异RN默认垂直排列Web默认水平排列避免布局错乱。所有文本必须放在Text组件内禁止直接在View中写文字否则会直接报错。长列表必须使用FlatList不要用ScrollView循环渲染避免性能问题和内存占用过高。样式使用StyleSheet.create统一管理不要直接写在行内提升性能和可维护性。调试使用Expo Go真机预览配合VS Code插件、React DevTools排查问题。页面跳转前必须先在导航器中注册路由否则会报路由不存在错误。兼容双端差异避免使用平台专属API如需使用可通过Platform.OS判断系统类型。五、课后作业基础作业安装Node.js与Expo脚手架创建RN项目成功启动开发服务用Expo Go真机预览Hello World页面。使用View、Text、StyleSheet编写基础页面实现垂直居中的标题与描述文本掌握Flex布局基础用法。安装React Navigation配置2个页面实现页面之间的跳转与返回。进阶作业使用FlatList渲染单词列表实现点击列表项跳转到详情页并传递单词数据。在详情页接收路由参数完整展示单词的英文、音标、中文释义。使用useEffect模拟异步请求数据实现页面加载时的初始化数据渲染。实战作业开发完整的RN单词学习App包含首页、单词列表页、单词详情页实现路由跳转、参数传递、列表渲染、样式美化可正常在iOS/Android双端预览运行代码规范、注释完整符合RN开发标准。上一课微信小程序实战 实战作业代码代码功能说明本实战作业基于微信小程序原生语法开发完整的单词学习小程序覆盖课程全部核心知识点。项目包含首页、单词列表页、单词详情页3个核心页面配置底部TabBar导航实现网络请求获取单词数据、本地缓存离线存储、页面跳转与参数传递、列表渲染、加载状态与异常处理全流程。代码严格遵循小程序开发规范适配微信平台规则包含空数据提示、错误Toast、加载动画等用户体验优化可直接在微信开发者工具中运行完整演示小程序从项目搭建到功能实现的全流程帮助巩固小程序开发核心技能。注意事项必须使用微信开发者工具打开项目使用测试号或已注册的小程序AppID创建项目。所有页面必须在app.json的pages数组中注册否则无法访问。正式发布前必须在微信公众平台配置request合法域名测试阶段可在开发者工具中关闭「不校验合法域名」选项。页面数据更新必须使用this.setData()直接修改this.data无法触发视图刷新。列表渲染wx:for必须搭配wx:key推荐使用唯一id避免仅用index作为key。页面跳转TabBar页面必须使用wx.switchTab不可使用wx.navigateTo。小程序对包体积有严格限制静态资源需压缩避免超过2M主包限制。发布前需完成用户隐私协议配置否则无法正常使用网络、存储等接口。完整实战代码项目结构wechat-word-miniprogram/ ├── app.js ├── app.json ├── app.wxss ├── sitemap.json ├── pages/ │ ├── index/ // 首页TabBar页面 │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ ├── list/ // 单词列表页TabBar页面 │ │ ├── list.js │ │ ├── list.json │ │ ├── list.wxml │ │ └── list.wxss │ └── detail/ // 单词详情页 │ ├── detail.js │ ├── detail.json │ ├── detail.wxml │ └── detail.wxss └── utils/ └── request.js // 封装请求工具app.json全局配置{ pages: [ pages/index/index, pages/list/list, pages/detail/detail ], window: { backgroundTextStyle: light, navigationBarBackgroundColor: #42b983, navigationBarTitleText: 单词学习小程序, navigationBarTextStyle: white, backgroundColor: #f5f5f5 }, tabBar: { color: #666, selectedColor: #42b983, borderStyle: black, backgroundColor: #fff, list: [ { pagePath: pages/index/index, text: 首页, iconPath: , selectedIconPath: }, { pagePath: pages/list/list, text: 单词列表, iconPath: , selectedIconPath: } ] }, sitemapLocation: sitemap.json, lazyCodeLoading: requiredComponents }app.js全局入口App({ onLaunch() { console.log(小程序启动) }, globalData: { userInfo: null } })app.wxss全局样式page { background-color: #f5f5f5; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif; } .container { padding: 30rpx; } .tip { text-align: center; color: #999; font-size: 28rpx; padding: 60rpx 0; }utils/request.js请求封装// 基础域名上线替换为已备案的合法域名 const baseUrl https://xxx.com/api const request (options) { wx.showLoading({ title: 加载中..., mask: true }) return new Promise((resolve, reject) { wx.request({ url: baseUrl options.url, method: options.method || GET, data: options.data || {}, header: { Content-Type: application/json }, success: (res) { if (res.statusCode 200) { resolve(res.data) } else { wx.showToast({ title: 请求失败, icon: none }) reject(res) } }, fail: (err) { wx.showToast({ title: 网络异常, icon: none }) reject(err) }, complete: () { wx.hideLoading() } }) }) } // 导出GET/POST方法 export const get (url, data) request({ url, method: GET, data }) export const post (url, data) request({ url, method: POST, data })pages/index/index首页index.wxmlview classcontainer home view classlogo-box text classtitle单词学习小程序/text text classdesc每天积累一个单词轻松提升词汇量/text /view view classtoday-word wx:if{{todayWord}} text classword-en{{todayWord.en}}/text text classword-phonetic{{todayWord.phonetic}}/text text classword-cn{{todayWord.cn}}/text /view button classenter-btn typeprimary bindtapgoToList查看全部单词/button /viewindex.jsimport { get } from ../../utils/request.js Page({ data: { todayWord: null }, onLoad() { this.getTodayWord() }, // 获取今日单词 getTodayWord() { // 模拟请求可替换为真实接口 const mockWord { en: native, phonetic: /ˈneɪtɪv/, cn: 原生的本地的 } this.setData({ todayWord: mockWord }) // 真实接口请求示例 // get(/word/today).then(res { // this.setData({ todayWord: res.data }) // }) }, // 跳转到单词列表 goToList() { wx.switchTab({ url: /pages/list/list }) } })index.wxss.home { display: flex; flex-direction: column; align-items: center; padding-top: 120rpx; } .logo-box { text-align: center; margin-bottom: 80rpx; } .title { display: block; font-size: 48rpx; font-weight: bold; color: #333; margin-bottom: 20rpx; } .desc { font-size: 28rpx; color: #666; } .today-word { width: 90%; background: #fff; padding: 60rpx 40rpx; border-radius: 16rpx; text-align: center; margin-bottom: 80rpx; box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.05); } .word-en { display: block; font-size: 48rpx; font-weight: bold; color: #333; margin-bottom: 12rpx; } .word-phonetic { display: block; font-size: 28rpx; color: #666; margin-bottom: 20rpx; } .word-cn { font-size: 36rpx; color: #42b983; } .enter-btn { width: 80%; height: 88rpx; line-height: 88rpx; border-radius: 44rpx; }pages/list/list单词列表页list.wxmlview classcontainer !-- 加载状态 -- view classtip wx:if{{loading}}正在加载单词列表.../view !-- 单词列表 -- view wx:else view wx:for{{wordList}} wx:keyid classword-item bindtapgoToDetail >list.jsimport { get } from ../../utils/request.js Page({ data: { wordList: [], loading: false }, onShow() { this.getWordList() }, // 获取单词列表 getWordList() { this.setData({ loading: true }) // 模拟数据可替换为真实接口 const mockList [ { id: 1, en: apple, phonetic: /ˈæpl/, cn: 苹果 }, { id: 2, en: banana, phonetic: /bəˈnɑːnə/, cn: 香蕉 }, { id: 3, en: orange, phonetic: /ˈɒrɪndʒ/, cn: 橙子 }, { id: 4, en: react, phonetic: /riˈækt/, cn: 反应前端框架 }, { id: 5, en: native, phonetic: /ˈneɪtɪv/, cn: 原生的 }, { id: 6, en: javascript, phonetic: /ˈdʒɑːvəskrɪpt/, cn: JavaScript脚本语言 } ] setTimeout(() { this.setData({ wordList: mockList, loading: false }) // 缓存单词列表 wx.setStorageSync(wordList, mockList) }, 800) // 真实接口请求示例 // get(/word/list).then(res { // this.setData({ wordList: res.data, loading: false }) // wx.setStorageSync(wordList, res.data) // }).catch(() { // // 读取缓存兜底 // const cache wx.getStorageSync(wordList) // if (cache) this.setData({ wordList: cache }) // this.setData({ loading: false }) // }) }, // 跳转到详情页 goToDetail(e) { const item e.currentTarget.dataset.item wx.navigateTo({ url: /pages/detail/detail?item${encodeURIComponent(JSON.stringify(item))} }) } })list.wxss.word-item { background: #fff; padding: 30rpx; border-radius: 12rpx; margin-bottom: 20rpx; display: flex; justify-content: space-between; align-items: center; } .word-info { display: flex; flex-direction: column; gap: 8rpx; } .en { font-size: 32rpx; font-weight: 500; color: #333; } .phonetic { font-size: 24rpx; color: #999; } .cn { font-size: 28rpx; color: #42b983; }pages/detail/detail单词详情页detail.wxmlview classcontainer view classdetail-card text classen{{wordInfo.en}}/text text classphonetic{{wordInfo.phonetic}}/text view classdivider/view text classcn{{wordInfo.cn}}/text /view button bindtapgoBack classback-btn返回列表/button /viewdetail.jsPage({ data: { wordInfo: {} }, onLoad(options) { // 接收并解析路由参数 if (options.item) { const wordInfo JSON.parse(decodeURIComponent(options.item)) this.setData({ wordInfo }) // 设置导航栏标题 wx.setNavigationBarTitle({ title: wordInfo.en }) } }, // 返回上一页 goBack() { wx.navigateBack() } })detail.wxss.container { padding: 40rpx; display: flex; flex-direction: column; align-items: center; } .detail-card { width: 100%; background: #fff; padding: 80rpx 40rpx; border-radius: 16rpx; text-align: center; margin-bottom: 60rpx; box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.05); } .en { display: block; font-size: 56rpx; font-weight: bold; color: #333; margin-bottom: 16rpx; } .phonetic { display: block; font-size: 32rpx; color: #666; margin-bottom: 40rpx; } .divider { width: 60rpx; height: 4rpx; background: #42b983; margin: 0 auto 40rpx; border-radius: 2rpx; } .cn { font-size: 40rpx; color: #42b983; } .back-btn { width: 80%; }运行方式打开微信开发者工具选择「不使用云服务」用测试号创建小程序项目。将上述代码按项目结构复制到对应文件中。点击「编译」按钮即可在模拟器中预览运行效果也可扫码在真机预览。测试阶段在开发者工具详情中勾选「不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书」。作业验收标准项目可正常编译运行无控制台报错页面正常显示。TabBar切换流畅页面跳转、参数传递、返回功能正常。单词列表正常渲染详情页可正确展示对应单词信息。加载状态、空数据提示、错误提示正常展示用户体验完整。代码规范注释清晰符合微信小程序开发标准。网络请求、本地缓存功能正常离线可读取缓存数据。