React Native安卓应用出现Possible Unhandled Promise Rejection错误如何修复
问题根源
你遇到的Possible Unhandled Promise Rejection报错核心原因是异步请求没有添加错误捕获逻辑:调用getMovie、getTv时如果请求失败(比如传入的ID是剧集ID时调用电影查询接口会返回404错误),Promise抛出的异常没有被catch捕获,就会触发这个报错。
同时你的代码还存在几个逻辑问题:
- 初始化
movieDetail、movieTv的state为数组,但接口返回的是对象,后续访问movieDetail.title会出现逻辑隐患 - 两个并行的请求接口会互相覆盖
loaded状态,可能出现数据没加载完就提前标记为加载完成的问题 - 组件return之后的
console.log(movieTv.success)永远不会执行,属于无效代码 - 没有判断路由参数是否存在的边界逻辑,极端情况会出现取空值报错
修复后的代码
Detail.js
import React, {useEffect, useState} from 'react'; import {Text, ActivityIndicator} from 'react-native'; import {getMovie, getTv} from '../services/services'; const Detail = ({route, navigation}) => { // 路由参数边界判断 if (!route.params?.movieDetail?.id) { return <Text>参数错误</Text> } const movieId = route.params.movieDetail.id; // 初始化state改为空对象,匹配接口返回类型 const [movieDetail, setMovieDetail] = useState({}); const [movieTv, setMovieTv] = useState({}); const [loaded, setLoaded] = useState(false); // 新增错误状态用于展示请求异常情况 const [error, setError] = useState(null); useEffect(() => { // 统一处理两个并行请求 const fetchData = async () => { const [movieRes, tvRes] = await Promise.allSettled([ getMovie(movieId), getTv(movieId) ]) // 处理电影请求结果 if (movieRes.status === 'fulfilled' && movieRes.value) { setMovieDetail(movieRes.value) } // 处理剧集请求结果 if (tvRes.status === 'fulfilled' && tvRes.value) { setMovieTv(tvRes.value) } setLoaded(true) } // 全局捕获请求异常 fetchData().catch(err => { setError(err.message) setLoaded(true) }) }, [movieId]); // 加载中状态 if (!loaded) { return <ActivityIndicator size="large" style={{flex: 1, justifyContent: 'center'}} /> } // 请求错误状态 if (error) { return <Text>加载失败:{error}</Text> } return ( <React.Fragment> {movieDetail.title ? <Text>{movieDetail.title}</Text> : <Text>{movieTv.name || '暂无数据'}</Text>} </React.Fragment> ); } export default Detail;
可选优化(services.js增加统一错误捕获)
如果你想统一处理所有接口的报错,也可以直接在请求封装层添加异常捕获逻辑:
import axios from 'axios'; const apiUrl = 'https://api.themoviedb.org/3'; const apiKey = 'api_key=31a7f8174b1e2c29744ec644af796973'; // 获取热门电影 export const getPopularMovies = async () => { try { const resp = await axios.get(`${apiUrl}/movie/popular?${apiKey}`); return resp.data.results; } catch (err) { console.error('获取热门电影失败', err) return [] } }; // 获取即将上映电影 export const getUpcomingMovies = async () => { try { const resp = await axios.get(`${apiUrl}/movie/upcoming?${apiKey}`); return resp.data.results; } catch (err) { console.error('获取即将上映电影失败', err) return [] } }; // 获取热门剧集 export const getPopularTv = async () => { try { const resp = await axios.get(`${apiUrl}/tv/popular?${apiKey}`); return resp.data.results; } catch (err) { console.error('获取热门剧集失败', err) return [] } }; export const getFamilyMovies = async () => { try { const resp = await axios.get(`${apiUrl}/discover/movie?${apiKey}&with_genres=10751`); return resp.data.results; } catch (err) { console.error('获取家庭类电影失败', err) return [] } }; export const getMovie = async id => { try { const resp = await axios.get(`${apiUrl}/movie/${id}?${apiKey}`); return resp.data; } catch (err) { console.error('获取电影详情失败', err) return null } }; export const getTv = async id => { try { const resp = await axios.get(`${apiUrl}/tv/${id}?${apiKey}`); return resp.data; } catch (err) { console.error('获取剧集详情失败', err) return null } };
修复说明
- 所有异步请求都添加了异常捕获逻辑,从根源解决未处理的Promise rejection报错
- 用
Promise.allSettled并行处理两个详情请求,不管其中一个是否成功都能正常返回结果,同时统一管理加载状态,避免状态被覆盖的问题 - 补充了加载中、请求失败的边界状态展示,避免白屏
- 修正了state初始化类型不匹配的问题
- 补充了路由参数非空判断,避免极端情况出现空值报错
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

