Diagnosing Missing Params in React Navigation Screen Transitions
Screen opens but route.params is undefined after push or replace? Check the param object, key names, deep link config, navigator version, and re-render resets in order.
12 Nov 2025, 10:55 UTC

Recognizable condition
A screen opens after navigation.push or navigation.replace, but route.params is undefined or the expected key is missing. The transition itself succeeds—the target screen mounts and renders—yet any data that depends on the passed parameter is blank, falls back to a default, or triggers a crash. This typically happens on secondary screens, not on the initial route.
Cause and diagnostic table
Use the clues below to narrow the failure before changing code.
| Likely cause | Diagnostic clue |
|---|---|
| Param object omitted or malformed in the navigation call | Source code calls navigate('Screen') with no second argument, or passes a non-object |
| Key mismatch between sender and receiver | route.params exists but the specific key is undefined |
| Deep linking configuration omitted | Param arrives via in-app navigation but not when opening from an external URL |
| Navigator version or API mismatch | Function component reads this.props.route.params or project is on React Navigation below 5.0 |
| State reset on re-render | Param appears briefly, then disappears after a re-render or focus event |
Ordered checks
1. Verify the param object in the navigation call
React Navigation accepts params as the second argument to push, replace, and navigate. Confirm the source screen passes a plain object with the exact key the target screen expects.
// Source screen
navigation.push('Profile', { userId: '42' });
If the second argument is missing, the target route receives an empty params object.
2. Check that key names match exactly
Log the received object on the target screen and compare it with the sender. Keys are case-sensitive.
// Target screen
import { useRoute } from '@react-navigation/native';
function ProfileScreen() {
const route = useRoute();
console.log(route.params); // Expect { userId: '42' }
const userId = route.params?.userId;
return <Text>{userId ?? 'No user'}</Text>;
}
If route.params is present but userId is undefined, rename the key in either the sender or receiver.
3. Inspect deep linking configuration
When a screen is opened from an external URL, params are parsed from the path pattern, not from a JavaScript object. The linking config must declare the parameter.
const linking = {
prefixes: ['myapp://'],
config: {
screens: {
Profile: 'profile/:userId',
},
},
};
If the path pattern is profile without :userId, the URL parameter is dropped and route.params.userId is undefined.
4. Confirm navigator version and hook usage
React Navigation 6 standardized the hook API. In function components, use useRoute() rather than reading this.props.route. Class components can still access this.props.route, but mixing patterns often causes undefined params during refactors. Verify the installed version in package.json:
npm ls @react-navigation/native
Run this in the project root. If the version is below 5.0, param handling differs and an upgrade is required.
5. Inspect for state reset on re-render
If the param appears and then vanishes, a parent re-render or a navigation.reset may be replacing the route without preserving params. Check for effect hooks that dispatch navigation actions on every render, and ensure params are included in any reset action.
Fixes tied to findings
- Missing param object: Add the object literal as the second argument:
navigation.push('Profile', { userId: '42' }). - Key mismatch: Rename the sender key or update the receiver to match. Use
route.params?.userIdto avoid crashes while debugging. - Deep link omission: Add the path parameter to the linking config, e.g.
Profile: 'profile/:userId'. - Version or API mismatch: Upgrade to React Navigation 6+ and migrate function components to
useRoute(). - Re-render reset: Move navigation side effects into
useFocusEffector guard them so they run once, and include params in anyresetpayload.
Practical verification
After applying a fix, verify on both Android and iOS:
- On the target screen, add
console.log(route.params)and confirm the expected key/value pair appears. - Trigger the transition from the source screen with a known param, e.g.
navigation.push('Profile', { userId: '42' }). - If deep links are used, open the app with a URL such as
myapp://profile/42and confirmroute.params.userIdis'42'. - Repeat on both platforms to rule out platform-specific parsing differences.
Remove debug logs once the param is stable.
Escalation criteria
Escalate to a deeper review when:
- The param is still absent after confirming the navigation call, key names, deep link config, and version.
- You use a custom navigator that wraps React Navigation and may intercept or rebuild route state.
- TypeScript types for the navigator do not include the param, causing compile-time gaps that hide runtime issues.
- You suspect a breaking change in React Navigation itself; check the official issue tracker for known regressions in your exact version.
When escalating, include the navigation call, the target screen's useRoute usage, the linking config snippet, and the installed React Navigation version.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.