You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native导航与Promise未处理拒绝问题求助

解决"Possible Unhandled Promise Rejection"错误:useNavigation使用不当问题

问题根源

你遇到的错误主要来自两个核心问题:

  • 违反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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 18:45:48