做过 RN 的都知道,在 RN 开发里经常会有一个版本用到老的情况,因为在 RN 开发里最可怕的事情就是版本升级,而更可怕的则是"跨架构"版本升级, 特别是 RN 开始引入 New Architecture 之后,基本上很多老版本的项目就不动了。
但是随着商店政策要求,比如 16KB page size ,又或者想适配鸿蒙,都需要升级到具体版本。
或者你看 0.61.3 和 0.74.0 貌似也差不了很多,但是如果你去看官方提供的更新 Helper 时,就会发现甚至找不到 0.61 的支持:

而从实际更新时间看,这两个版本的跨度甚至超过五年 ,想从 6 升级到 7 ,需要处理包括各种原生配置,第三方包没人维护,API 弃用等一些列问题,这个难度实质上比 Flutter 1 升 Flutter 3 还难受 ,特别是 node_module
里各种包内依赖和不兼容问题,想想就让人放弃:

所以,在过去我肯定不会想去升级它,但是现在是 AI 时代,特别是 Github Copilot 现在还提供的 Agents 模式,你只需要选择一个项目,输入你想要实现的需求,然后它就会创建一个 [WIP]
的 PR 草稿,然后制定计划并执行修改:
因为之前已经完成 0.61 到 0.74 的升级,所以这里用升级到 0.80 的截图作为例子。
进入草稿,首先会看到 AI 正在开始理解需求并制定计划,你可以通过 session 查看当前进度,理解 Agent 现在正在做什么,是否符合你的预期:
之后,你就可以看到 Agent 给你罗列出来的升级计划,并开始针对计划逐步完成你的需求,Copilot Agent 在这里最大的优势就是它本身就是 Github 体系,所以它可以很好的理解你整个项目的构成,甚至理解过去每次提交更改和其他项目的关系:

接着, Agent 就会开始调整代码,并通过运行模块或者单元测试来验证修改的准确性 ,这个过程可能会有幻觉,或者说方向跑偏的问题,只要一开始方向跑偏了,后续大概率都是无用的调整,所以其实每次都点进去 session 看看它在做什么,会节省很多时间,如果发现跑偏了,可以提前停止这个会话:
完成后,你就会看到之前的计划变成了 PR 相关的修改总结,结果会告知你调整了什么东西,需要注意的有什么,然后你就可以 review 代码,也可以直接 clone 对应分支 copilot/xxxxx
在本地运行验证:

之后,如果还有问题,或者需要调整的时候,可以继续在下面回复,然后 Agent 会根据你的问题用新的 session 来完成新的需求,然后调整也会汇总到最开始的总结里。
所以这个升级过程,其实就是从跑不起来,到可以跑起来但是有一堆错误,再到可以看到界面,调整细节等,如果没有 AI,基本上做到一半都是放弃的结果,而实际上,从 0.61.3 升级到 0.74.0 一共消耗了 40 次 Agent,整个过程一共有 49 个提交,涉及文件修改 99 个:
而这次 AI 的修改,有一些地方还是挺有意思的,比如某些库已经停止维护了,但是有一些简单的调整就可以让项目跑起来,所以 AI 直接采用 patch 文件模式修复问题,通过配置 "postinstall": "patch-package"
,然后引入某些库的指定 git patch ,这样在 npm install 的时候,就会对 module apply 对应修改,从而规避问题:

本意就是让项目先能正常运行再说。
另外,在 RN 的依赖升级里,最麻烦的就是第三方库兼容,在实际体验过程中,AI 引入的库升级,其实很多时候可能没有对应上版本要求,只能说 RN 的库和 RN 的版本依赖性太强,只要稍微匹配不上就都是 Error ,AI 有时候也没有那么细节:
vbnet
FAILURE: Build failed with an exception.
Where:
Build file '*******\GSYGithubAPP\node_modules\react-native-reanimated\android\build.gradle' line: 386
What went wrong:
Execution failed for task ':react-native-reanimated:assertMinimalReactNativeVersionTask'.
[Reanimated] Unsupported React Native version. Please use 75. or newer.
当然,有些库 AI 一直觉得可以适配,但是实际在根本无法兼容,比如 react-native-scrollable-tab-view
依赖的各个库版本和 API 都太低,根本无法直接适配,所以我让 AI 直接替换为新的实现,这才是 AI 的优势:

react-native-router-flux
同样如此,让 AI 使用替代方案后,它直接适配到 navigation 方案,并通过自己写的单元测试来验证修改是否可以运行:
虽然这些类型的迁移后续还需要手工修改,但是确实大量优化了适配的时间和方向。
当然,AI 最得心应手的应该是对这种 API 的调整适配,基本上它自己要自己找官方资料,然后就可以批量调整项目里的所有 API :

类似的还有配置问题,比如遇到了在 android 上打包失败的问题,才发现现在 RN 新版本现在打包都需要配置到 4G 以上内存以上:

当然,AI 有时候也会做些搞笑的时候,比如都执行了 6 分钟了,它才发现自己一直测试不成功的原因是忘了安装 node_module ,有时候一些时间就是这么浪费的:

另外就是在对于 iOS 的打包问题上,因为 Agent 环境没有 Xcode ,所以它没办法直接验证结果,只能用户自己验证,对比 Android ,iOS 的问题解决上确实疲弱:

当然,如果没有 AI 的支持,实际上想做 RN 从 0.61.3 到 0.74.0 的升级对我来说几乎不可能,因为各种失败和修改都会是一个极度消费耐心的过程,而有了 AI 之后,事实上手动调整的部分只剩下 20% 不到,而且 AI 的修改不一定对,但是确实可以提供有用的方向。
最后,下方是本次 AI + 人力在成功完成 0.61.3 升级到 0.74.0 的总结,如果没体验过 Copilot Agent 的,强烈推荐体验一下,确实和 Cursor Agent 有不一样的感受,至少之前我用 Trae 和 Cursor 尝试升级都失败了,只能说 Github Copilot Agent 依托 Github 平台的优势还是很明显。
Github Copilot Agent 修改总结
This PR successfully upgrades the GSYGithubAPP project from React Native 0.61.3 to 0.74.0, bringing the app up to date with 5 years of React Native improvements and modernizing the entire development stack.
🚀 Major Version Updates
React Native : 0.61.3 → 0.74.0
React : 16.9.0 → 18.2.0
Android Build Tools : Updated to Gradle 8.6, compileSdk 34, Java 11
iOS: Updated Podfile to modern format
🔧 Critical Runtime Error Fixes
Complete ViewPropTypes and Text.propTypes Compatibility Resolution
Fixed the "Cannot read property 'style' of undefined" runtime error and app registration failures caused by third-party packages importing deprecated prop types from 'react-native'. In React Native 0.74, both ViewPropTypes
and Text.propTypes
were completely removed, causing these packages to fail at runtime.
Packages patched with complete compatibility fixes:
react-native-scrollable-tab-view-fix-guo
(3 files: index.js, ScrollableTabBar.js, DefaultTabBar.js)@react-native-community/masked-view
(MaskedViewTypes.js)react-native-htmlview
(HTMLView.js)
Lottie Animation Compatibility Fix
Fixed critical runtime errors in LottieView components that were causing app crashes and preventing animations from executing:
javascript
// Before: Using incorrect animatedProgress prop (doesn't work in lottie-react-native 6.7.0)
<LottieView animatedProgress={this.state.progress} />
// After: Using correct progress prop for Animated.Value + useNativeDriver
<LottieView progress={this.state.progress} />
Animated.timing(this.state.progress, {
toValue: 1,
duration: 2000,
useNativeDriver: false, // Required to prevent warning
}).start();
Resolved errors:
- ✅ "Cannot add new property '_tracking'" TypeError
- ✅ "ReadableNativeMap cannot be cast to java.lang.Double" native Android error
- ✅ "useNativeDriver was not specified" warnings
- ✅ Animations now execute correctly - both welcome and login Lottie animations function properly
Marked.js API Compatibility Fix
Fixed "Invalid RegExp: Invalid escape" runtime error in markdown processing caused by API changes in marked v12.0+:
javascript
// Before: marked v11.x and earlier API
return marked(dataPre);
// After: marked v12.0+ API
return marked.parse(dataPre);
Resolved errors:
- ✅ "Invalid RegExp: Invalid escape" error in marked.umd.js
- ✅ Markdown rendering in README and issue content now works correctly
- ✅ Updated both
changeServiceResult
andgenerateMd2Html
functions in htmlUtils.js
AppState API Compatibility Fix
Fixed "AppState.removeEventListener is not a function" error in DynamicPage.js caused by React Native 0.74 API changes:
javascript
// Before: React Native 0.61 API
AppState.addEventListener('change', this._handleAppStateChange);
AppState.removeEventListener('change', this._handleAppStateChange);
// After: React Native 0.74 API
this.appStateSubscription = AppState.addEventListener('change', this._handleAppStateChange);
this.appStateSubscription.remove();
Resolved errors:
- ✅ "AppState.removeEventListener is not a function" runtime error
- ✅ Proper cleanup of AppState listeners prevents memory leaks
🔄 Complete Navigation System Modernization
Successfully replaced react-native-router-flux with React Navigation v6:
The outdated react-native-router-flux
(v4.3.1) was causing numerous compatibility issues with React Native 0.74 and is no longer maintained. This migration provides a future-proof navigation solution.
Architecture Transformation
- Modern Navigation Stack: Implemented React Navigation v6 with proper NavigationContainer, Stack, Tab, and Drawer navigators
- Full Compatibility Layer: Created NavigationService maintaining all existing Actions.* API calls (226+ method calls throughout the app)
- Component Migration: Updated 40+ component files with new navigation imports while preserving all functionality
- Complete Actions.refresh Implementation: Fixed missing refresh functionality for dynamic header updates and language switching
- Dependency Cleanup: Completely removed react-native-router-flux and associated patches
Key Technical Implementation
javascript
// Before: react-native-router-flux
import { Actions } from 'react-native-router-flux';
Actions.PersonPage({ currentUser: userName });
Actions.refresh({ titleData: res.data }); // Update header with new data
// After: React Navigation v6 (same API maintained)
import { Actions } from '../navigation/Actions';
Actions.PersonPage({ currentUser: userName }); // Works identically
Actions.refresh({ titleData: res.data }); // Now works correctly with setParams
The NavigationService provides seamless backward compatibility with Bottom Tab Navigation, Stack Navigation, Drawer Navigation, Modal Stack, and proper Actions.refresh support.
📱 Modern Tab Navigation Implementation
Replaced incompatible react-native-scrollable-tab-view-fix-guo with React Navigation Material Top Tabs:
The old scrollable tab view package was incompatible with React Native 0.74, causing "Element type is invalid" runtime errors in RepositoryDetailPage and NotifyPage.
Technical Migration
javascript
// Before: Using deprecated scrollable-tab-view
import ScrollableTabView, {DefaultTabBar} from 'react-native-scrollable-tab-view-fix-guo';
<ScrollableTabView renderTabBar={() => <DefaultTabBar />}>
<Component tabLabel="Tab 1" />
</ScrollableTabView>
// After: Using React Navigation Material Top Tabs
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
const Tab = createMaterialTopTabNavigator();
<Tab.Navigator>
<Tab.Screen name="Tab1" component={Component} options={{ tabBarLabel: "Tab 1" }} />
</Tab.Navigator>
Updated Components:
- ✅ RepositoryDetailPage: Readme, Activity, Files, Issues tabs now use Material Top Tabs
- ✅ NotifyPage: Unread, Participating, All notification tabs modernized
- ✅ Maintains identical visual styling with primary color theme and white indicators
- ✅ Preserves all existing functionality and component references
🎯 Status Bar and Navigation Header Layout Fix
Resolved critical UI layout issue where status bar overlapped with navigation headers:
After migrating from react-native-router-flux to React Navigation v6, the status bar was overlapping with navigation headers throughout the app, causing poor user experience and usability issues.
Root Cause & Solution
React Navigation v6 handles status bars differently than react-native-router-flux, requiring proper SafeAreaProvider integration and consistent StatusBar management.
Technical implementation:
javascript
// Global status bar configuration in AppNavigator
<SafeAreaProvider>
<StatusBar
hidden={false}
backgroundColor={'transparent'}
translucent
barStyle={'light-content'}
/>
<NavigationContainer>
<RootNavigator />
</NavigationContainer>
</SafeAreaProvider>
UI Layout Fixes:
- ✅ Global StatusBar Management: Added SafeAreaProvider wrapper with consistent status bar configuration
- ✅ Safe Area Integration: React Navigation v6 with SafeAreaProvider handles safe areas automatically
- ✅ Removed Redundant StatusBar Components: Cleaned up conflicting StatusBar components from individual screens
- ✅ Consistent Header Heights: Navigation headers now properly account for status bar space on all devices
- ✅ Fixed Navigation Flow: Resolved welcome page navigation blocking caused by StatusBar configuration conflicts
🔍 SearchDrawer Functionality Restoration
Fixed SearchDrawer not appearing in SearchPage after router-flux migration:
The search filter functionality was lost during the navigation system migration. The SearchDrawer component existed but was not accessible to users.
Root Cause & Solution
In the old react-native-router-flux implementation, the SearchDrawer was automatically integrated with a drawer icon. React Navigation v6 requires explicit drawer button configuration.
Technical implementation:
javascript
// Updated CustomDrawerButton to use React Navigation hooks
function CustomDrawerButton() {
const navigation = useNavigation();
const handlePress = () => {
if (navigation.openDrawer) {
navigation.openDrawer();
}
};
return (
<TouchableOpacity onPress={handlePress}>
<Icon name={'filter'} size={20} color={Constant.miWhite}/>
</TouchableOpacity>
);
}
// Added drawer button to SearchPage header in AppNavigator
<Stack.Screen
name="SearchPage"
component={SearchDrawer}
options={{
title: I18n('search'),
headerRight: () => <CustomDrawerButton />,
}}
/>
SearchDrawer Restoration:
- ✅ Filter Button Added: SearchPage now displays filter button in navigation header
- ✅ Drawer Opens Correctly: Tapping filter button opens SearchDrawer from right side
- ✅ Filter Functionality Restored: Users can filter search results by type, sort, and language
- ✅ Maintained Visual Design: Filter button matches original styling and placement
⚠️ React String Refs Deprecation Warnings Completely Eliminated
Converted all deprecated string refs to createRef() throughout the application:
React 18 deprecated string refs (ref="componentName"
) in favor of the createRef() pattern. The app had 88+ instances of deprecated string ref usage causing console warnings.
Comprehensive String Refs Migration
javascript
// Before: Deprecated string refs (React 16 pattern)
class MyComponent extends Component {
componentDidMount() {
if (this.refs.pullList) {
this.refs.pullList.showRefreshState();
}
}
render() {
return <PullListView ref="pullList" />;
}
}
// After: Modern createRef pattern (React 18 compatible)
class MyComponent extends Component {
constructor(props) {
super(props);
this.pullListRef = React.createRef();
}
componentDidMount() {
if (this.pullListRef.current) {
this.pullListRef.current.showRefreshState();
}
}
render() {
return <PullListView ref={this.pullListRef} />;
}
}
Components Updated:
- ✅ SearchPage: Converted pullList string ref to createRef
- ✅ DynamicPage: Converted pullList string ref to createRef
- ✅ TrendPage: Converted pullList string ref to createRef
- ✅ IssueDetailPage: Converted pullList string ref to createRef
- ✅ ListPage: Converted pullList string ref to createRef
- ✅ PushDetailPage: Converted pullList string ref to createRef
- ✅ RepositoryDetailActivityPage: Converted pullList string ref to createRef
- ✅ RepositoryDetailFilePage: Converted pullList and listHeader string refs to createRef
- ✅ RepositoryIssueListPage: Converted pullList string ref to createRef
- ✅ CodeDetailPage: Converted pullList string ref to createRef
- ✅ BasePersonPage: Converted pullList string ref to createRef
Results:
- ✅ Zero React 18 warnings about deprecated string refs
- ✅ 88+ ref instances updated across 11 component files
- ✅ Identical functionality maintained - all list operations work as before
- ✅ Future-proof code - compatible with future React versions
🏗️ Redux Architecture Cleanup
Fixed Redux require cycle warnings by refactoring store architecture:
The Redux store had circular dependency issues where all reducer files were importing createReducer
from the main store index file, while the store index file was importing all the reducers, creating require cycles.
Technical Solution
javascript
// Before: Circular dependency
// app/store/index.js exports createReducer → app/store/reducers/index.js imports reducers →
// app/store/reducers/login.js imports createReducer from ../index.js → circular dependency
// After: Clean separation
// Created app/store/reducerUtils.js with createReducer
// All reducers import from reducerUtils.js
// Store index.js imports and re-exports createReducer from reducerUtils.js
Architecture Improvements:
- ✅ Extracted Utility Function : Moved
createReducer
to dedicatedapp/store/reducerUtils.js
file - ✅ Updated All Reducers : Modified login.js, user.js, event.js, repository.js, and issue.js to import from
../reducerUtils
- ✅ Maintained API Compatibility : Store index.js re-exports
createReducer
to maintain existing imports - ✅ Eliminated Require Cycles: Resolved all 5 require cycle warnings in Redux store files
React Navigation Warning Resolution:
- ✅ Removed Incorrect paddingTop Usage : Eliminated manual
paddingTop
adjustments inheaderStyle
that were causing warnings - ✅ Proper Safe Area Handling: React Navigation v6 with SafeAreaProvider handles safe areas automatically without manual intervention
- ✅ Clean Navigation Configuration: Simplified header configurations across Tab, Stack, and Drawer navigators
📱 Android Build Configuration Updates
- ✅ Updated Gradle configuration for React Native 0.74 compatibility
- ✅ Increased JVM memory allocation to 6GB for React Native 0.74 builds
- ✅ Fixed react-native-reanimated version compatibility (3.8.1 for RN 0.74)
- ✅ Removed deprecated Flipper integration causing build failures
🧪 Validation Results
- ✅ JavaScript bundling works: Metro successfully generates bundles without errors
- ✅ Android configuration: Gradle builds complete without compatibility issues
- ✅ Navigation flows: All 20+ screens, modals, and navigation patterns functional
- ✅ Welcome page navigation: Fixed blocking issue preventing transition from welcome to main app
- ✅ Actions.refresh functionality: Dynamic header updates and language switching work correctly
- ✅ Runtime error resolution: All major runtime errors eliminated including marked.js RegExp errors and AppState API issues
- ✅ React warnings resolved: No more deprecated string ref warnings
- ✅ Lottie animations functional: Both welcome and login animations work correctly
- ✅ Modern tab navigation: Repository detail and notification pages with tabbed interfaces render correctly
- ✅ Markdown rendering: README and issue content display correctly with updated marked API
- ✅ Clean architecture: Removed deprecated dependencies and unnecessary patches
- ✅ Status bar layout fixed: No more overlapping between status bar and navigation headers
- ✅ AppState compatibility: Fixed listener management for React Native 0.74
- ✅ SearchDrawer functionality: Filter button opens search drawer correctly
- ✅ String refs eliminated: Zero React 18 deprecation warnings
- ✅ Redux architecture clean: No more require cycle warnings between store and reducer files
- ✅ Navigation warnings resolved: Eliminated paddingTop warnings with proper SafeAreaProvider usage