ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

React Native实战:从零构建记忆翻牌游戏,解决启动白屏等常见问题

React Native实战:从零构建记忆翻牌游戏,解决启动白屏等常见问题 之前想用 React Native 做一个轻量级的移动端小游戏发现很多教程要么太旧要么只讲基础组件完整项目流程和实际开发中的坑点讲得不够。本文将以一个经典的《记忆翻牌游戏》为例手把手带你从零搭建一个完整的 React Native 应用覆盖环境搭建、核心组件使用、游戏逻辑实现、状态管理、样式布局以及如何解决开发中常见的“启动白屏”等问题。无论你是刚接触 React Native 的新手还是想了解如何构建一个完整移动端项目的开发者都能从本文获得可直接复用的代码和清晰的思路。1. 背景与核心概念1.1 什么是 React NativeReact Native (简称 RN) 是一个由 Facebook 推出的开源移动应用框架。它允许开发者使用 JavaScript 和 React 的语法来构建真正的原生移动应用iOS 和 Android。其核心原理是开发者编写的 JavaScript 代码会通过一个“桥接”Bridge与原生平台如 Objective-C/Swift, Java/Kotlin进行通信最终渲染成平台原生的 UI 组件。这意味着你既能享受到 Web 前端高效的开发体验和热更新又能获得接近原生应用的性能和用户体验。1.2 为什么选择 React Native 开发游戏对于《记忆翻牌游戏》这类 UI 交互密集、逻辑相对独立、对极致性能要求不是最高的休闲游戏React Native 是一个性价比很高的选择跨平台一套代码可以同时运行在 iOS 和 Android 上极大节省开发和维护成本。开发效率高基于 React 组件化思想UI 构建快速支持热重载Hot Reloading修改代码后能立即看到效果无需重新编译。生态丰富拥有庞大的 npm 生态系统可以方便地引入各种第三方库来处理动画、状态、存储等。原生体验最终渲染的是原生视图手势响应、滚动体验等都与原生应用无异。当然对于需要复杂 3D 渲染、超高帧率或重度依赖特定原生硬件功能的游戏可能仍需考虑原生开发或 Unity 等游戏引擎。1.3 《记忆翻牌游戏》项目简介记忆翻牌游戏也称 Concentration、Pairs是一个经典的益智游戏。游戏规则通常如下屏幕上呈现多张扣着的牌。玩家每次点击翻开两张牌。如果两张牌图案相同则配对成功牌保持翻开状态。如果图案不同则牌会在一小段时间后自动翻回去。游戏目标是翻开所有牌完成所有配对用时或步数越少越好。我们将使用 React Native 来实现这个游戏涵盖洗牌、翻牌动画、匹配判断、计时、计步等核心功能。2. 环境准备与版本说明在开始编码前我们需要搭建好 React Native 的开发环境。请注意React Native 的版本和配套工具更新较快以下配置以当前撰写时稳定版本为例请根据官方文档随时调整。2.1 核心环境与工具操作系统macOS (开发 iOS 必备)Windows 或 Linux (主要开发 Android)。本文示例命令在 macOS 下编写Windows 用户请注意路径差异。Node.js推荐使用 LTS 版本如18.x或20.x。可使用node -v检查。包管理器npm 或 yarn。本文使用 npm。Watchman(macOS/Linux 推荐)用于监听文件变化提升开发效率。Java Development Kit (JDK)Android 开发需要。推荐 JDK 17 或 21。Android 开发环境Android Studio用于安装 Android SDK 和创建模拟器。Android SDK确保安装了必要的 SDK 平台和构建工具。iOS 开发环境(仅 macOS)Xcode从 Mac App Store 安装用于编译 iOS 应用和运行模拟器。CocoaPodsiOS 依赖管理工具。2.2 React Native 版本与项目初始化我们将使用 React Native 社区推荐的、更现代化的开发方式——React Native CLI配合新架构New Architecture的模板。这种方式对新手更友好项目结构更清晰。首先安装 React Native CLI 工具全局安装一次即可npm install -g react-native-cli然后使用 CLI 创建一个新的项目。我们指定一个较新的稳定版本模板例如 0.73npx react-native init MemoryCardGame --version 0.73.6命令解释npx用于执行 npm 包中的命令避免全局安装的版本冲突。react-native init初始化新项目。MemoryCardGame你的项目名称。--version 0.73.6指定 React Native 版本建议使用最新的稳定版。创建成功后进入项目目录cd MemoryCardGame项目结构大致如下MemoryCardGame/ ├── android/ # Android 原生代码目录 ├── ios/ # iOS 原生代码目录 ├── node_modules/ # 项目依赖 ├── __tests__/ # 测试文件 ├── .eslintrc.js # ESLint 配置 ├── .prettierrc.js # Prettier 配置 ├── app.json # 项目配置文件 ├── babel.config.js # Babel 配置 ├── index.js # 应用入口文件 ├── metro.config.js # Metro 打包器配置 ├── package.json # 项目依赖和脚本 └── tsconfig.json # TypeScript 配置如果创建时选择了TS2.3 运行项目到模拟器/真机Android:确保 Android 模拟器已启动可通过 Android Studio 的 AVD Manager 创建和启动或者安卓手机已通过 USB 连接并开启调试模式。在项目根目录运行npx react-native run-android此命令会启动 Metro 打包服务器并尝试在连接的设备或模拟器上安装并运行应用。iOS(macOS only):确保 Xcode 已安装并打开ios/MemoryCardGame.xcworkspace文件选择合适的模拟器如 iPhone 15。在项目根目录运行npx react-native run-ios或者直接在 Xcode 中点击运行按钮。如果一切顺利你应该能看到默认的 React Native 欢迎界面。至此开发环境准备完毕。3. 核心语法、配置与原理拆解在开始游戏开发前我们需要理解几个 React Native 的核心概念和我们将用到的关键组件。3.1 核心组件View, Text, Image, TouchableOpacityReact Native 提供了一系列基础组件来构建界面它们会映射到原生的 UIView、TextView 等。View相当于 Web 中的div是最基础的容器组件用于布局和样式。Text用于显示文本。所有文本都必须放在Text组件内不能直接在View里写文字。Image用于显示图片。支持网络图片和本地图片资源。TouchableOpacity一个包装器使其子组件能够响应触摸事件并且触摸时有透明度的视觉反馈。这是我们实现“可点击的牌”的关键。3.2 样式StyleSheetReact Native 使用 JavaScript 对象来定义样式类似于 Web 的 CSS-in-JS。使用StyleSheet.create来创建样式对象有利于性能优化和代码提示。import { StyleSheet } from react-native; const styles StyleSheet.create({ container: { flex: 1, justifyContent: center, alignItems: center, backgroundColor: #f0f0f0, }, card: { width: 80, height: 120, borderRadius: 8, backgroundColor: #4a90e2, justifyContent: center, alignItems: center, margin: 5, }, });3.3 状态管理useState Hook游戏的状态如哪些牌被翻开、当前分数、游戏是否结束是随时间变化的。React 的useStateHook 是管理组件内部状态的首选工具。import React, { useState } from react; import { View, Text } from react-native; function Game() { // 定义一个状态 score 和更新它的函数 setScore初始值为 0 const [score, setScore] useState(0); const handlePress () { // 点击后分数加1 setScore(score 1); }; return ( View Text当前分数: {score}/Text {/* 一个可以触发 handlePress 的组件 */} /View ); }3.4 副作用与生命周期useEffect Hook当我们需要在组件渲染后执行一些操作如初始化游戏数据、启动计时器、监听事件或者在某些状态变化时执行清理工作如清除计时器就需要使用useEffectHook。import React, { useState, useEffect } from react; function Timer() { const [seconds, setSeconds] useState(0); useEffect(() { // 组件挂载后设置一个间隔为1秒的计时器 const intervalId setInterval(() { setSeconds(s s 1); }, 1000); // 返回一个清理函数在组件卸载时清除计时器 return () clearInterval(intervalId); }, []); // 空依赖数组表示此 effect 只在组件挂载和卸载时运行 return Text已用时: {seconds} 秒/Text; }4. 完整实战构建《记忆翻牌游戏》现在让我们将上述知识整合起来一步步构建游戏。4.1 项目结构与数据准备首先我们在项目根目录创建一个src文件夹并在其中创建几个文件来组织代码src/ ├── components/ │ └── Card.js # 单张卡牌组件 ├── screens/ │ └── GameScreen.js # 游戏主屏幕 ├── constants/ │ └── cards.js # 卡牌数据 └── styles/ └── global.js # 全局样式1. 定义卡牌数据 (src/constants/cards.js)我们用一个数组来代表一副牌每张牌包含唯一ID、图案标识和是否被翻开/匹配的状态。// src/constants/cards.js export const initialCards [ { id: 1, symbol: , isFlipped: false, isMatched: false }, { id: 2, symbol: , isFlipped: false, isMatched: false }, { id: 3, symbol: , isFlipped: false, isMatched: false }, { id: 4, symbol: , isFlipped: false, isMatched: false }, { id: 5, symbol: , isFlipped: false, isMatched: false }, { id: 6, symbol: , isFlipped: false, isMatched: false }, { id: 7, symbol: , isFlipped: false, isMatched: false }, { id: 8, symbol: , isFlipped: false, isMatched: false }, { id: 9, symbol: , isFlipped: false, isMatched: false }, { id: 10, symbol: , isFlipped: false, isMatched: false }, { id: 11, symbol: , isFlipped: false, isMatched: false }, { id: 12, symbol: , isFlipped: false, isMatched: false }, ]; // 一个简单的洗牌函数 export const shuffleArray (array) { let shuffled [...array]; for (let i shuffled.length - 1; i 0; i--) { const j Math.floor(Math.random() * (i 1)); [shuffled[i], shuffled[j]] [shuffled[j], shuffled[i]]; } return shuffled; };2. 创建全局样式 (src/styles/global.js)定义一些可复用的样式。// src/styles/global.js import { StyleSheet } from react-native; export const globalStyles StyleSheet.create({ screenContainer: { flex: 1, paddingTop: 50, paddingHorizontal: 20, backgroundColor: #f5f5f5, }, title: { fontSize: 28, fontWeight: bold, textAlign: center, marginBottom: 20, color: #333, }, gameInfoContainer: { flexDirection: row, justifyContent: space-between, marginBottom: 20, paddingHorizontal: 10, }, infoText: { fontSize: 18, fontWeight: 600, color: #555, }, cardGrid: { flexDirection: row, flexWrap: wrap, justifyContent: center, }, button: { backgroundColor: #007AFF, paddingVertical: 12, paddingHorizontal: 30, borderRadius: 25, alignItems: center, marginTop: 30, }, buttonText: { color: white, fontSize: 18, fontWeight: bold, }, });4.2 实现单张卡牌组件 (src/components/Card.js)这是游戏的核心 UI 单元。它需要响应点击并根据状态显示牌背或牌面图案。// src/components/Card.js import React from react; import { View, Text, TouchableOpacity, StyleSheet } from react-native; const Card ({ card, onPress, disabled }) { // card: { id, symbol, isFlipped, isMatched } // onPress: 点击卡牌时触发的函数 // disabled: 是否禁用点击例如在动画或匹配检查期间 return ( TouchableOpacity onPress{onPress} disabled{disabled || card.isFlipped || card.isMatched} style{styles.touchable} activeOpacity{0.7} // 点击时的透明度 View style{[styles.card, card.isFlipped || card.isMatched ? styles.cardFront : styles.cardBack]} {(card.isFlipped || card.isMatched) ? ( Text style{styles.symbol}{card.symbol}/Text ) : ( Text style{styles.cardBackText}?/Text )} /View /TouchableOpacity ); }; const styles StyleSheet.create({ touchable: { margin: 6, // 卡牌之间的间距 }, card: { width: 70, height: 100, borderRadius: 10, justifyContent: center, alignItems: center, // 阴影效果增加立体感 shadowColor: #000, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 3.84, elevation: 5, // Android 阴影 }, cardFront: { backgroundColor: #FFFFFF, borderWidth: 3, borderColor: #4a90e2, }, cardBack: { backgroundColor: #4a90e2, }, symbol: { fontSize: 36, }, cardBackText: { fontSize: 28, color: #FFFFFF, fontWeight: bold, }, }); export default Card;4.3 实现游戏主逻辑屏幕 (src/screens/GameScreen.js)这是游戏的大脑负责管理所有状态卡牌、分数、时间、已翻牌和游戏逻辑。// src/screens/GameScreen.js import React, { useState, useEffect, useCallback } from react; import { View, Text, TouchableOpacity, Alert } from react-native; import Card from ../components/Card; import { initialCards, shuffleArray } from ../constants/cards; import { globalStyles } from ../styles/global; const GameScreen () { // 游戏核心状态 const [cards, setCards] useState(shuffleArray([...initialCards])); const [flippedCards, setFlippedCards] useState([]); // 存储当前翻开的两张牌的索引 const [moves, setMoves] useState(0); // 移动步数 const [time, setTime] useState(0); // 游戏用时秒 const [gameStarted, setGameStarted] useState(false); // 游戏是否开始计时器 const [isProcessing, setIsProcessing] useState(false); // 是否正在处理匹配逻辑防止连续点击 // 初始化或重置游戏 const resetGame useCallback(() { setCards(shuffleArray([...initialCards])); setFlippedCards([]); setMoves(0); setTime(0); setGameStarted(false); setIsProcessing(false); }, []); // 处理卡牌点击 const handleCardPress useCallback((index) { // 如果正在处理、牌已翻开、已匹配或是同一张牌则忽略点击 if (isProcessing || cards[index].isFlipped || cards[index].isMatched) { return; } // 开始游戏第一次点击时启动计时器 if (!gameStarted) { setGameStarted(true); } // 翻开当前卡牌 const newCards [...cards]; newCards[index].isFlipped true; setCards(newCards); const newFlippedCards [...flippedCards, index]; setFlippedCards(newFlippedCards); // 如果翻开了两张牌检查是否匹配 if (newFlippedCards.length 2) { setIsProcessing(true); // 开始处理禁用点击 const [firstIndex, secondIndex] newFlippedCards; if (cards[firstIndex].symbol cards[secondIndex].symbol) { // 匹配成功 setTimeout(() { const matchedCards [...newCards]; matchedCards[firstIndex].isMatched true; matchedCards[secondIndex].isMatched true; setCards(matchedCards); setFlippedCards([]); setIsProcessing(false); checkGameOver(matchedCards); // 检查游戏是否结束 }, 500); // 给一点时间让玩家看到匹配结果 } else { // 匹配失败翻回去 setTimeout(() { const resetCards [...newCards]; resetCards[firstIndex].isFlipped false; resetCards[secondIndex].isFlipped false; setCards(resetCards); setFlippedCards([]); setIsProcessing(false); }, 1000); // 给玩家记忆的时间 } // 无论成功与否步数加1 setMoves(prev prev 1); } }, [cards, flippedCards, isProcessing, gameStarted]); // 检查游戏是否结束所有牌都匹配 const checkGameOver (currentCards) { const allMatched currentCards.every(card card.isMatched); if (allMatched) { setGameStarted(false); // 停止计时 Alert.alert( 恭喜, 你赢了\n用时: ${time} 秒\n步数: ${moves} 步, [{ text: 再玩一次, onPress: resetGame }] ); } }; // 计时器 Effect useEffect(() { let intervalId; if (gameStarted) { intervalId setInterval(() { setTime(prev prev 1); }, 1000); } return () { if (intervalId) clearInterval(intervalId); }; }, [gameStarted]); // 游戏初始化 useEffect(() { resetGame(); }, []); // 空依赖仅在组件挂载时运行一次 return ( View style{globalStyles.screenContainer} Text style{globalStyles.title}记忆翻牌游戏/Text View style{globalStyles.gameInfoContainer} Text style{globalStyles.infoText}步数: {moves}/Text Text style{globalStyles.infoText}时间: {time} 秒/Text /View View style{globalStyles.cardGrid} {cards.map((card, index) ( Card key{card.id} card{card} onPress{() handleCardPress(index)} disabled{isProcessing} / ))} /View TouchableOpacity style{globalStyles.button} onPress{resetGame} Text style{globalStyles.buttonText}重新开始/Text /TouchableOpacity /View ); }; export default GameScreen;4.4 修改应用入口并运行现在我们需要修改项目的入口文件将我们的GameScreen设置为根组件。修改App.js(位于项目根目录)// App.js import React from react; import GameScreen from ./src/screens/GameScreen; function App() { return GameScreen /; } export default App;保存所有文件。确保你的 Metro 开发服务器正在运行如果之前运行npx react-native run-android/ios它应该已经在运行了。然后在模拟器或真机上你应该能看到游戏界面。首次运行可能遇到的问题如果遇到Unable to resolve module错误可能是因为新创建的src目录没有被 Metro 正确识别。可以尝试在项目根目录执行以下命令重启 Metro 服务器在终端按Ctrl C停止当前 Metro 服务器。运行npm start -- --reset-cache清除缓存并重启。然后重新运行npx react-native run-android或npx react-native run-ios。4.5 运行结果说明成功运行后你将看到一个包含以下元素的游戏界面顶部标题“记忆翻牌游戏”。上方显示当前的游戏步数和用时。中间是一个网格布局的卡牌区域所有牌初始为蓝色牌背显示“”。点击一张牌它会翻过来显示一个动物表情符号。点击另一张牌如果图案相同两张牌会保持翻开状态边框高亮如果不同两张牌会在1秒后翻回去。每次尝试翻开两张牌步数会增加1。游戏时间从第一次点击牌开始计时。当所有牌都成功配对后会弹出一个提示框显示本次游戏用时和步数并可以点击“再玩一次”重新开始。底部的“重新开始”按钮可以随时重置游戏。至此一个功能完整的《记忆翻牌游戏》就构建完成了。5. 常见问题与排查思路在 React Native 开发中尤其是初学者很容易遇到一些典型问题。下面结合我们的游戏项目和通用开发经验列出常见问题及解决方案。问题现象常见原因解决思路启动白屏/红屏错误 (React Native 启动白屏)1. Metro 服务器未启动或连接失败。2. JavaScript 代码有语法错误或运行时错误。3. 原生依赖未正确链接或安装如 iOS 的 Pods。4. 设备/模拟器与开发服务器网络不通。1.检查 Metro 服务器终端应显示“Metro waiting on ...”。如果没有在项目根目录运行npm start。2.查看错误信息红屏会显示具体错误栈。根据提示修复 JS 代码错误。3.iOS Pods 安装进入ios目录运行pod install然后重新run-ios。4.检查网络确保设备/模拟器与电脑在同一网络或使用adb reverse(Android) 或手动配置 IP (npx react-native start --host [你的IP])。npx react-native run-android失败1. Android SDK 路径未配置或版本不对。2. 模拟器未启动或设备未连接。3. 端口被占用如 8081。4. Gradle 构建失败依赖冲突等。1.检查环境变量确认ANDROID_HOME或ANDROID_SDK_ROOT已正确设置。2.启动模拟器通过 Android Studio AVD Manager 启动或使用emulator -avd [模拟器名称]。3.杀死占用端口进程lsof -i :8081找到 PID然后kill -9 [PID]。4.清理 Gradle在android目录下运行./gradlew clean然后重新run-android。npx react-native run-ios失败1. Xcode 版本与 React Native 版本不兼容。2. CocoaPods 未安装或版本过旧。3. iOS 模拟器版本问题。4. 证书或签名问题。1.更新 Xcode确保使用兼容的 Xcode 版本。2.安装/更新 CocoaPodssudo gem install cocoapods然后在ios目录运行pod install。3.选择正确模拟器在 Xcode 中检查 scheme 或通过--simulator参数指定如npx react-native run-ios --simulatoriPhone 15。4.检查签名在 Xcode 中为项目设置正确的 Team 和 Bundle Identifier。热重载 (Hot Reload) 不工作1. 开发菜单未启用。2. Metro 配置问题。1.摇一摇设备或按快捷键iOS模拟器CmdD, Android模拟器CmdM打开开发菜单确保“Enable Hot Reloading”已勾选。2. 尝试重启 Metro 服务器 (npm start -- --reset-cache)。图片资源无法加载1. 路径错误。2. 图片尺寸过大或格式不支持。3. Android 上未将资源链接到原生端。1. 对于本地图片使用require(./path/to/image.png)语法并确保路径正确。2. 优化图片大小使用常见格式PNG, JPG。3. 对于 Android如果图片放在android/app/src/main/res/下需要重新编译。通常建议将图片放在项目根目录的assets文件夹中管理。样式不生效或布局错乱1. 样式属性拼写错误RN 样式是驼峰命名如backgroundColor。2. Flexbox 布局理解有误。3. 组件未设置flex: 1导致容器高度为0。1. 仔细检查样式对象中的属性名。2. 复习 Flexbox 布局概念flexDirection,justifyContent,alignItems是核心。3. 确保最外层容器或需要撑满屏幕的组件设置了flex: 1。游戏逻辑 bug牌点一次就匹配flippedCards状态更新逻辑有误可能将同一张牌的索引加入了两次或者匹配检查时机不对。仔细检查handleCardPress函数。确保在翻开第二张牌后setIsProcessing(true)能有效防止后续点击。检查flippedCards数组是否正确地只包含当前翻开的两张牌的索引。可以使用console.log打印关键状态来调试。6. 最佳实践与工程建议将一个小游戏跑起来只是第一步。要让项目更健壮、可维护、体验更好我们需要关注以下工程化实践。6.1 状态管理优化我们的游戏逻辑目前全部放在GameScreen组件中对于这个规模的项目是合适的。但如果状态变得更复杂例如多个屏幕、用户配置、游戏历史可以考虑引入状态管理库如Zustand、Redux Toolkit或MobX将游戏状态逻辑抽离到独立的 Store 中。6.2 性能优化列表渲染优化如果卡牌数量非常多比如 100 张使用FlatList或FlashList来自 Shopify替代简单的map渲染它们会回收屏幕外的组件极大提升滚动性能。避免不必要的重渲染使用React.memo包装Card组件并确保其onPress回调使用useCallback包裹我们已经做了避免每次父组件渲染时都创建新的函数引用导致子组件不必要的重渲染。图片优化如果使用网络图片或大量本地图片考虑使用像react-native-fast-image这样的库来优化加载和缓存。6.3 动画增强我们目前使用setTimeout来实现简单的翻牌和匹配反馈。为了更流畅的体验应该使用 React Native 自带的Animated API或更强大的react-native-reanimated库来实现真正的翻转动画。// 使用 Animated 实现翻转的简化示例思路 import { Animated } from react-native; // 在 Card 组件内部定义动画值 const flipAnimation useRef(new Animated.Value(0)).current; // 根据 flipAnimation 的值来 interpolate 旋转角度和透明度 // 在 onPress 时触发 Animated.spring 或 Animated.timing6.4 代码结构与可维护性组件拆分我们已经将Card拆分为独立组件。还可以考虑将GameInfo显示步数和时间和ResetButton也拆分成更小的、可复用的组件。常量提取将卡牌数量、动画时长、颜色值等魔法数字提取到src/constants/下的文件中。自定义 Hook可以将计时器逻辑useEffect和游戏状态重置逻辑resetGame抽离成自定义 Hook如useGameTimer和useGameState使GameScreen更清晰。6.5 测试为关键的游戏逻辑函数如shuffleArray, 匹配检查编写单元测试使用 Jest。为组件编写渲染测试使用 React Native Testing Library。6.6 样式与主题使用StyleSheet.create集中管理样式是个好习惯。对于大型项目可以引入类似styled-components的库或者建立一套设计系统定义好颜色、字体、间距等主题常量。6.7 关于“国内使用 React Native 有哪些限制”这是一个常被问到的问题。主要限制和注意事项包括原生依赖与第三方库一些优秀的第三方库可能主要维护者在国外更新可能不及时或对国内特色功能如微信登录、支付宝支付、国内地图支持不够。需要寻找社区维护的替代品或自己封装。热更新React Native 的热更新能力如 CodePush在国内安卓市场审核时可能受到更严格的审查需要准备完备的合规说明。iOS 则禁止在 App Store 审核指南明确禁止的更新方式。性能与包体积对于非常复杂的交互或对性能有极致要求的页面可能需要编写原生模块来优化。初始的 APK/IPA 包体积会比纯原生或 Flutter 稍大。开发环境安装依赖npm install和原生库CocoaPods时可能会因为网络问题速度慢或失败。配置国内镜像源如淘宝 npm 镜像是必备技能。社区与文档官方文档和主流社区如 Stack Overflow, GitHub Issues以英文为主。中文资料虽然丰富但质量参差不齐且可能过时需要具备查阅官方英文文档的能力。尽管如此React Native 在开发电商、社交、工具、内容类 App 的中前台页面时依然具有极高的效率和成本优势被许多国内大厂如腾讯、字节、美团在部分业务线上使用。通过这个《记忆翻牌游戏》项目我们不仅学会了 React Native 的基础还实践了状态管理、组件通信、副作用处理和基础样式。你可以在此基础上继续扩展比如增加难度选择、添加音效、引入更复杂的动画、记录最高分到本地存储甚至接入后端服务。动手修改和添加功能是巩固学习的最佳方式。
返回列表