React Native导航与Promise未处理拒绝问题求助
问题根源
你遇到的错误主要来自两个核心问题:
- 违反React Hook调用规则:
useNavigation是React Hook,它只能在函数组件的顶层作用域或者自定义Hook的顶层调用,绝对不能放在async异步函数(你的check函数)这类嵌套函数里执行,这会破坏Hook的调用顺序规则,直接引发异常。 - Navigation上下文不可用:你的
App组件是NavigationContainer的父级(useNavigation调用在NavigationContainer的渲染范围之外),而useNavigation依赖NavigationContainer提供的上下文,在这个位置调用根本拿不到有效的navigation实例,自然会抛出未处理的Promise拒绝错误。
修复方案
这里提供两种简单可行的修复方式,你可以根据场景选择:
方案1:将check函数移到HomeScreen组件内(最推荐)
既然HomeScreen已经通过props拿到了navigation实例,直接用它就行,完全不需要额外调用useNavigation,代码改动最小:
// App.js 移除check函数,简化Screen配置 const App = () => { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={HomeScreen} /> <Stack.Screen name="New" component={NewScreen} /> </Stack.Navigator> </NavigationContainer> ); } // screens.js 把check逻辑移入HomeScreen export function HomeScreen({ navigation }) { const check = async () => { try { const response = await apiCall(); console.log(response); navigation.navigate("New"); // 注意:你的Screen名称是"New",不是"NewScreen" } catch(err) { console.log("Caught: " + err); } }; return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Button title="Next" onPress={check} /> </View> ); }
额外提醒:你之前写的
navigation.navigate("NewScreen")是错误的,Stack.Screen的name属性是"New",必须和这个值保持一致才能正确跳转。
方案2:通过NavigationContainer的ref获取实例(适合App层级处理导航的场景)
如果你确实需要在App组件里处理导航逻辑,可以给NavigationContainer添加ref来获取有效的navigation实例,避开Hook的使用限制:
const App = () => { const navigationRef = React.useRef(null); const check = async () => { try { const response = await apiCall(); console.log(response); // 使用可选链避免ref未初始化时的调用错误 navigationRef.current?.navigate("New"); } catch(err) { console.log("Caught: " + err); } }; return ( <NavigationContainer ref={navigationRef}> <Stack.Navigator> <Stack.Screen name="Home"> {(props) => ( <HomeScreen {...props} check={check} /> )} </Stack.Screen> <Stack.Screen name="New" component={NewScreen} /> </Stack.Navigator> </NavigationContainer> ); }
额外优化:修复apiCall的错误处理逻辑
看你的server.js里的apiCall函数,还有个潜在问题:当response.ok为false时,你创建新Promise的写法会导致错误无法被外层catch捕获,建议改成直接throw错误:
export const apiCall = async () => { try { const response = await fetch(global.SITE + "/ttt.php", { method: 'POST', headers: { 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Authorization': 'Basic ' + base64.encode(global.BASICAUTHUSER + ':' + global.BASICAUTHPWD) } }); console.log(response); if (!response.ok) { throw new Error(`HTTP Error: ${response.status}`); // 直接throw错误,外层catch会捕获 } return response.json(); } catch(err) { throw err; // 重新抛出错误,让调用者的catch能处理 }; };
原来的return err会把错误作为成功的返回值,导致check函数的catch块永远捕获不到apiCall的错误,这也是引发未处理Promise拒绝的潜在原因。
内容的提问来源于stack exchange,提问作者Mick
相关产品推荐
相关产品推荐

