as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
Ring
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

步骤4: 代码迁移

步骤4: 代码迁移

4.1 移除PropTypes

React 19移除了React程序包中的PropTypes。所有PropTypes均须迁移到TypeScript界面中使用。

查找所有PropTypes使用情况

grep -rn "from 'prop-types'" src/
grep -rn "\.propTypes\s*=" src/

迁移模式

// ❌ 之前(RN 0.83中不可用)
import PropTypes from 'prop-types';

function UserCard({ name, email, age, onPress }) {
  return (
    <TouchableOpacity onPress={onPress}>
      <View>
        <Text>{name}</Text>
        <Text>{email}</Text>
        {age && <Text>Age: {age}</Text>}
      </View>
    </TouchableOpacity>
  );
}

UserCard.propTypes = {
  name: PropTypes.string.isRequired,
  email: PropTypes.string.isRequired,
  age: PropTypes.number,
  onPress: PropTypes.func,
};

// ✅ 之后
interface UserCardProps {
  name: string;
  email: string;
  age?: number;
  onPress?: () => void;
}

function UserCard({ name, email, age, onPress }: UserCardProps) {
  return (
    <TouchableOpacity onPress={onPress}>
      <View>
        <Text>{name}</Text>
        <Text>{email}</Text>
        {age && <Text>Age: {age}</Text>}
      </View>
    </TouchableOpacity>
  );
}

4.2 替换defaultProps

React 19移除了对函数组件的defaultProps支持。改用默认参数值。

查找所有defaultProps使用情况

grep -rn "\.defaultProps\s*=" src/

迁移模式

// ❌ 之前
MyComponent.defaultProps = {
  name: 'Default',
  age: 0,
  onPress: () => {},
};

// ✅ 之后 — 使用默认参数
function MyComponent({ 
  name = 'Default', 
  age = 0, 
  onPress = () => {} 
}: MyComponentProps) {
  return <Text>{name}</Text>;
}

4.3 替换BackHandler.removeEventListener

React Native已移除BackHandler.removeEventListener()。使用订阅模式。

查找所有使用情况

grep -rn "BackHandler.removeEventListener" src/

迁移模式

// ❌ 之前(在RN 0.83中崩溃)
BackHandler.addEventListener('hardwareBackPress', handler);
// ... 稍后
BackHandler.removeEventListener('hardwareBackPress', handler);

// ✅ 之后 — 订阅模式
const subscription = BackHandler.addEventListener('hardwareBackPress', handler);
// ... 稍后
subscription.remove();

在含有useEffect的React组件中

useEffect(() => {
  const subscription = BackHandler.addEventListener('hardwareBackPress', () => {
    // 处理返回键按下事件
    return true; // 防止默认行为
  });

  return () => subscription.remove();
}, []);

4.4 修复useNativeDriver混用问题

RN 0.72不支持混合使用原生驱动和JS驱动的动画,但只会发出警告。在RN 0.83中,这种混用行为会引发致命崩溃 (SIGABRT)。

以下两条规则均须强制执行:

  1. 按值: 单一的Animated.Value在其整个生命周期内的所有动画中必须使用同一驱动。
  2. 按视图(新增): 合并到同一Animated.View的同一样式对象中的所有Animated.Value实例必须使用同一驱动。

审核您的项目

grep -rn "useNativeDriver" src/

出现两次以上的文件最有可能包含混合驱动视图。

崩溃模式示例

// ❌ 崩溃 — 同一视图上的scaleAnim(原生驱动)与backgroundAnim(JS驱动)
<Animated.View style={{
  transform: [{ scale: scaleAnim }],             // useNativeDriver: true
  backgroundColor: backgroundAnim.interpolate()  // useNativeDriver: false
}}>
  {/* 内容 */}
</Animated.View>

// ✅ 正确做法 — 按驱动类型拆分为嵌套视图
<Animated.View style={{ transform: [{ scale: scaleAnim }], opacity: opacityAnim }}>
  {/* 原生驱动:transform、opacity */}
  <Animated.View style={{ backgroundColor: colorAnim.interpolate(...) }}>
    {/* JS驱动:backgroundColor */}
    {/* 内容 */}
  </Animated.View>
</Animated.View>

驱动使用规则

  • 原生驱动 (useNativeDriver: true):transformopacity。请勿将所有useNativeDriver: true一概改为false。仅修复存在冲突的值。
  • JS驱动 (useNativeDriver: false):backgroundColorwidthheight、color interpolations

4.5 更新旧版上下文API使用情况

React 19完全移除了旧版上下文API(childContextTypesgetChildContext)。使用现代上下文API:

// ❌ 之前 — 旧版上下文(已移除)
class Parent extends React.Component {
  getChildContext() {
    return { theme: 'dark' };
  }
  static childContextTypes = { theme: PropTypes.string };
}

// ✅ 之后 — 现代化上下文API
const ThemeContext = React.createContext('light');

function Parent({ children }) {
  return (
    <ThemeContext.Provider value="dark">
      {children}
    </ThemeContext.Provider>
  );
}

function Child() {
  const theme = useContext(ThemeContext);
  return <Text>{theme}</Text>;
}

4.6 添加显式React挂钩导入

如有任何文件使用了挂钩但未显式导入,均会因ReferenceError: useState未定义错误而失败。

// ✅ 始终显示导入挂钩
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';

发现潜在问题

grep -rn "useState\|useEffect\|useCallback\|useMemo\|useRef" src/ | grep -v "import"

4.7 移除不兼容的工具

部分开发工具无法兼容React 19:

# 移除@welldone-software/why-did-you-render(声明了peer react@^18)
npm卸载@welldone-software/why-did-you-render

检查是否有其他开发依赖项将react@^18固定为对等依赖项:

npm ls react 2>&1 | grep "peer"

4.8 更新SafeAreaView使用情况

React Native 0.83要求将react-native-safe-area-context作为依赖项。更新应用的根组件:

// ✅ 之后 — 在SafeAreaProvider中包装应用
import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context';

function App() {
  return (
    <SafeAreaProvider>
      <AppContent />
    </SafeAreaProvider>
  );
}

function AppContent() {
  const insets = useSafeAreaInsets();
  
  return (
    <View style={{ 
      flex: 1,
      paddingTop: insets.top,
      paddingBottom: insets.bottom,
    }}>
      {/* 您的应用内容 */}
    </View>
  );
}

4.9 将布局值转换为密度无关像素 (DIP)

Vega上的React Native 0.83对所有布局值使用密度无关像素 (dp)。画布参考尺寸为960×540dp,在1080p显示屏上的比例系数为2。该框架会自动将dp值缩放为物理像素。

将所有硬编码的像素值除以比例系数(1080p设备上的系数为2)。

// ❌ 之前 (RN 0.72) — 物理像素值
const styles = StyleSheet.create({
  container: {
    width: 1920,
    height: 1080,
    padding: 32,
  },
  title: {
    fontSize: 48,
    marginBottom: 24,
  },
});

// ✅ 之后 (RN 0.83) — dp值,除以2
const styles = StyleSheet.create({
  container: {
    width: 960,
    height: 540,
    padding: 16,
  },
  title: {
    fontSize: 24,
    marginBottom: 12,
  },
});

Last updated: 2026年8月4日