Amazon Developer

as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
Ring
AWS
Documentation
Support
Contact Us
My Cases
Get Started
Design and Develop
Publish
Reference
Support

Step 4: Code Migration

4.1 Remove PropTypes

React 19 removes PropTypes from the React package. All PropTypes usage must be migrated to TypeScript interfaces.

Find all PropTypes usage

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

Migration pattern

// ❌ BEFORE (breaks in 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,
};

// ✅ AFTER
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 Replace defaultProps

React 19 removes defaultProps support for function components. Use default parameter values instead.

Find all defaultProps usage

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

Migration pattern

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

// ✅ AFTER — use default parameters
function MyComponent({ 
  name = 'Default', 
  age = 0, 
  onPress = () => {} 
}: MyComponentProps) {
  return <Text>{name}</Text>;
}

4.3 Replace BackHandler.removeEventListener

BackHandler.removeEventListener() was removed by React Native. Use the subscription pattern.

Find all usage

grep -rn "BackHandler.removeEventListener" src/

Migration pattern

// ❌ BEFORE (crashes in RN 0.83)
BackHandler.addEventListener('hardwareBackPress', handler);
// ... later
BackHandler.removeEventListener('hardwareBackPress', handler);

// ✅ AFTER — subscription pattern
const subscription = BackHandler.addEventListener('hardwareBackPress', handler);
// ... later
subscription.remove();

In a React component with useEffect

useEffect(() => {
  const subscription = BackHandler.addEventListener('hardwareBackPress', () => {
    // Handle back press
    return true; // Prevent default behavior
  });

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

4.4 Fix useNativeDriver mixed usage

In RN 0.72, mixing native-driver and JS-driver animations was unsupported but only produced warnings. In RN 0.83, this mixing causes a fatal crash (SIGABRT).

There are two rules, both enforced:

  1. Per-value: A single Animated.Value must use the same driver across all animations throughout its lifetime.
  2. Per-view (NEW): All Animated.Value instances combined into the same style object on a single Animated.View must use the same driver.

Audit your project

grep -rn "useNativeDriver" src/

Files with more than two occurrences are most likely to have mixed-driver views.

Example of the crash pattern

// ❌ CRASHES — scaleAnim (native) and backgroundAnim (JS) on same view
<Animated.View style={{
  transform: [{ scale: scaleAnim }],             // useNativeDriver: true
  backgroundColor: backgroundAnim.interpolate()  // useNativeDriver: false
}}>
  {/* content */}
</Animated.View>

// ✅ CORRECT — separate into nested views by driver type
<Animated.View style={{ transform: [{ scale: scaleAnim }], opacity: opacityAnim }}>
  {/* native-driven: transform, opacity */}
  <Animated.View style={{ backgroundColor: colorAnim.interpolate(...) }}>
    {/* JS-driven: backgroundColor */}
    {/* content */}
  </Animated.View>
</Animated.View>

Driver usage rules

  • Native driver (useNativeDriver: true): transform, opacity. Don't blanket-change all useNativeDriver: true to false. Only fix values where the conflict exists.
  • JS driver (useNativeDriver: false): backgroundColor, width, height, color interpolations

4.5 Update legacy Context API usage

React 19 fully removes the legacy Context API (childContextTypes, getChildContext). Use the modern Context API:

// ❌ BEFORE — Legacy Context (removed)
class Parent extends React.Component {
  getChildContext() {
    return { theme: 'dark' };
  }
  static childContextTypes = { theme: PropTypes.string };
}

// ✅ AFTER — Modern Context 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 Add explicit React hook imports

If any files use hooks without importing them explicitly, they fail with ReferenceError: useState is not defined error.

// ✅ Always import hooks explicitly
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';

Find potential issues

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

4.7 Remove incompatible tools

Some development tools are incompatible with React 19:

# Remove @welldone-software/why-did-you-render (declares peer react@^18)
npm uninstall @welldone-software/why-did-you-render

Check for any other dev dependencies that pin react@^18 as a peer dependency:

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

4.8 Update SafeAreaView usage

React Native 0.83 requires react-native-safe-area-context as a dependency. Update your app's root component:

// ✅ AFTER — wrap app in 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,
    }}>
      {/* Your app content */}
    </View>
  );
}

4.9 Convert layout values to density-independent pixels (DIP)

React Native 0.83 on Vega uses density-independent pixels (dp) for all layout values. The canvas reference size is 960x540 dp, which is a scale factor of 2 on 1080p displays. The framework automatically scales dp values to physical pixels.

Divide all hardcoded pixel values by the scale factor, which is 2 for 1080p devices.

// ❌ BEFORE (RN 0.72) — physical pixel values
const styles = StyleSheet.create({
  container: {
    width: 1920,
    height: 1080,
    padding: 32,
  },
  title: {
    fontSize: 48,
    marginBottom: 24,
  },
});

// ✅ AFTER (RN 0.83) — dp values, divided by 2
const styles = StyleSheet.create({
  container: {
    width: 960,
    height: 540,
    padding: 16,
  },
  title: {
    fontSize: 24,
    marginBottom: 12,
  },
});

Last updated: Aug 04, 2026