Expo中使用react-native-camera遇Possible Unhandled Promise Rejection错误求助
问题
在Expo中使用react-native-camera时出现错误:Possible Unhandled Promise Rejection (id: 0),代码如下:
import {StatusBar} from 'expo-status-bar'; import React from "react"; import { StyleSheet, Modal, View, Pressable, Text, SafeAreaView, Button, Image, PushNotificationIOS } from "react-native"; import { useEffect, useRef, useState } from 'react'; import Icon from "react-native-vector-icons/MaterialIcons"; import {shareAsync} from 'expo-sharing'; import * as MediaLibrary from 'expo-media-library'; import { Camera } from 'expo-camera'; export default function App() { let cameraRef = useRef(); const [hasCameraPermission, setHasCameraPermission] = useState(); const [hasMediaLibraryPermission, setHasMediaLibraryPermission] = useState(); const [photo, setPhoto] = useState(); useEffect(()=>{ (async ()=>{ const cameraPermission = await Camera.requestCameraPermissionsAsync(); constMediaLibraryPermission = await MediaLibrary.requestMediaLibraryPermissionsAsync(); setHasCameraPermission(cameraPermission.status === "granted"); setHasMediaLibraryPermission(MediaLibraryPermission.status === "granted"); })(); },[]); if (hasCameraPermission === undefined){ return <Text> Requesting permissions...</Text> } else if (!hasCameraPermission){ return <Text> Permission for camera not granted. Please change this in settinr.</Text> } let takePic = async () => { let options = { quality :1, base64: true, exif : false }; let newPhoto = await cameraRef.current.takePictureAsync(options); setPhoto(newPhoto); }; if(photo){ let sharePic = () => { shareAsync(photo.uri).then(() => { setPhoto(undefined); }); }; let savePhoto = () => { MediaLibrary.saveToLibraryAsync(photo.uri).then(() =>{ setPhoto(undefined); }); }; return ( <SafeAreaView style = {styles.container}> <Image style = {styles.preview} source = {{uri: "data:image/jpg;base64," + photo.base64}}/> <Button title = "share" onPress = {sharePic}/> {hasMediaLibraryPermission ? <Button title = "save" onPress = {savePhoto}/>:undefined} <Button title = "Discard" onPress = {()=> setPhoto(undefined)}/> </SafeAreaView> ) } return ( <Camera style={styles.container} ref = {cameraRef}> <View style = {styles.buttonContainer}> <Button title = "Takc Pic" onPress = {takePic} /> </View> <StatusBar style="auto" /> </Camera> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, buttonContainer:{ backgroundColor :'#fff', alignSelf:'flex-end' }, preview:{ alignSelf:'stretch', flex:1 } });
解决方案
错误核心原因
- 变量拼写错误:
constMediaLibraryPermission缺少空格,应为const mediaLibraryPermission,后续引用时误写为MediaLibraryPermission,导致未定义变量触发Promise拒绝。 - 异步操作无错误捕获:
takePictureAsync、shareAsync、saveToLibraryAsync这些异步方法可能抛出异常,未做处理会导致未捕获的Promise拒绝。 - 权限状态边界模糊:初始状态
hasCameraPermission为undefined,需确保权限请求完成后再渲染相机组件。
修复后的完整代码
import { StatusBar } from 'expo-status-bar'; import React from "react"; import { StyleSheet, Text, SafeAreaView, Button, Image } from "react-native"; import { useEffect, useRef, useState } from 'react'; import { shareAsync } from 'expo-sharing'; import * as MediaLibrary from 'expo-media-library'; import { Camera } from 'expo-camera'; export default function App() { const cameraRef = useRef(); const [hasCameraPermission, setHasCameraPermission] = useState(null); const [hasMediaLibraryPermission, setHasMediaLibraryPermission] = useState(null); const [photo, setPhoto] = useState(null); const [errorMsg, setErrorMsg] = useState(''); useEffect(() => { const requestPermissions = async () => { try { const cameraPermission = await Camera.requestCameraPermissionsAsync(); const mediaLibraryPermission = await MediaLibrary.requestMediaLibraryPermissionsAsync(); setHasCameraPermission(cameraPermission.status === "granted"); setHasMediaLibraryPermission(mediaLibraryPermission.status === "granted"); } catch (err) { setErrorMsg('权限请求失败:' + err.message); } }; requestPermissions(); }, []); if (errorMsg) { return <Text style={{ padding: 20 }}>{errorMsg}</Text>; } if (hasCameraPermission === null) { return <Text style={{ padding: 20 }}>请求权限中...</Text>; } else if (!hasCameraPermission) { return <Text style={{ padding: 20 }}>相机权限未授予,请在设置中修改。</Text>; } const takePic = async () => { try { if (!cameraRef.current) return; const options = { quality: 1, base64: true, exif: false }; const newPhoto = await cameraRef.current.takePictureAsync(options); setPhoto(newPhoto); } catch (err) { setErrorMsg('拍照失败:' + err.message); } }; if (photo) { const sharePic = async () => { try { await shareAsync(photo.uri); setPhoto(null); } catch (err) { setErrorMsg('分享失败:' + err.message); } }; const savePhoto = async () => { try { await MediaLibrary.saveToLibraryAsync(photo.uri); setPhoto(null); } catch (err) { setErrorMsg('保存失败:' + err.message); } }; return ( <SafeAreaView style={styles.container}> {errorMsg ? <Text style={{ color: 'red', padding: 10 }}>{errorMsg}</Text> : null} <Image style={styles.preview} source={{ uri: "data:image/jpg;base64," + photo.base64 }} /> <Button title="分享" onPress={sharePic} /> {hasMediaLibraryPermission ? <Button title="保存" onPress={savePhoto} /> : null} <Button title="取消" onPress={() => setPhoto(null)} /> </SafeAreaView> ); } return ( <Camera style={styles.container} ref={cameraRef}> {errorMsg ? <Text style={{ color: 'red', padding: 10, backgroundColor: 'white' }}>{errorMsg}</Text> : null} <View style={styles.buttonContainer}> <Button title="拍照" onPress={takePic} /> </View> <StatusBar style="auto" /> </Camera> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, buttonContainer: { backgroundColor: '#fff', alignSelf: 'flex-end', padding: 10, }, preview: { alignSelf: 'stretch', flex: 1, } });
内容的提问来源于stack exchange,提问作者이소민
相关产品推荐
相关产品推荐

