Expo路由传参:如何从props获取指定单值?
问题本质
报错核心是组件首次渲染时props.route.params可能为undefined,直接访问.image会触发"undefined is not an object"错误。另外代码还存在两个潜在问题:
- CameraButton组件导出名与文件名/导航注册名不匹配,可能导致导航逻辑异常
- AddPost里的
uploadImage函数引用了未定义的uri变量
修复步骤
1. 安全访问路由参数
在AddPost中,先判断props.route.params是否存在,再访问image属性,用可选链操作符?.是最简洁的方式:
const imageUri = props.route.params?.image;
或者用条件判断兼容旧环境:
const imageUri = props.route.params && props.route.params.image;
2. 修正CameraButton的组件导出名
CameraButton.js导出的组件名为App,改成和文件名一致的CameraButton,避免导航匹配错误:
// CameraButton.js export default function CameraButton() { // 替换原有的App函数名 // 原有逻辑不变 }
3. 完善AddPost的uploadImage函数
在uploadImage中使用获取到的图片URI,避免引用未定义变量:
const uploadImage = async () => { const imageUri = props.route.params?.image; if (!imageUri) { alert('请先选择或拍摄图片'); return; } const response = await fetch(imageUri); // 后续添加上传逻辑 }
完整修复代码
AddPost.js
import { useNavigation } from "@react-navigation/core"; import React, { useState } from 'react' import { View, TextInput, Button } from 'react-native' export default function AddPost(props) { console.log(props.route.params); // 打印参数确认 const navigation = useNavigation(); const [caption, setCaption] = useState("") const uploadImage = async () => { const imageUri = props.route.params?.image; if (!imageUri) { alert('请先选择或拍摄图片'); return; } const response = await fetch(imageUri); // 这里添加你的上传逻辑 } return ( <View style={{flex: 1}}> <TextInput placeholder="Whats on your mind Edgers navars" onChangeText={(caption) => setCaption(caption)} /> <Button title="Take A Photo" onPress={() => navigation.navigate("CameraButton")} /> <Button title="Save" onPress={() => uploadImage()} /> </View> ) }
CameraButton.js
import { Camera, CameraType } from 'expo-camera'; import { useNavigation } from "@react-navigation/core"; import { useState } from 'react'; import { Button, StyleSheet, Text, TouchableOpacity, View, Image } from 'react-native'; import * as ImagePicker from 'expo-image-picker'; // 修正组件导出名 export default function CameraButton() { const navigation = useNavigation(); const [type, setType] = useState(Camera.Constants.Type.back) const [permission, requestPermission] = Camera.useCameraPermissions(); const [image, setImage] = useState(null); const [camera, setCamera] = useState(null); const takePicture = async () => { if(camera){ const data = await camera.takePictureAsync(null); setImage(data.uri); } } if (!permission) { return <View />; } if (!permission.granted) { return ( <View style={styles.container}> <Text style={{ textAlign: 'center' }}> We need your permission to show the camera </Text> <Button onPress={requestPermission} title="grant permission" /> </View> ); } function toggleCameraType() { setType((current) => ( current === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back )); } let openImagePickerAsync = async () => { let permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (permissionResult.granted === false) { alert("Permission to access camera roll is required!"); return; } let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.All, allowsEditing: true, aspect: [4, 3], quality: 1, }); if (!result.cancelled) { setImage(result.uri); } } return ( <View style={styles.container}> <Camera ref={ref => setCamera(ref)} style={styles.camera} type={type}> <View style={styles.buttonContainer}> <TouchableOpacity style={styles.button} onPress={toggleCameraType}> <Text style={styles.text}>Flip Camera</Text> </TouchableOpacity> <TouchableOpacity style={styles.button} onPress={() => takePicture()}> <Text style={styles.text}>Take Picture</Text> </TouchableOpacity> <TouchableOpacity style={styles.button} onPress={openImagePickerAsync}> <Text style={styles.text}>Choose Picture</Text> </TouchableOpacity> <TouchableOpacity style={styles.button} onPress={() => navigation.navigate('AddPost', {image})}> <Text style={styles.text}>Save Picture</Text> </TouchableOpacity> </View> </Camera> {image && <Image source={{uri: image}} style={styles.camera}/>} </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', }, camera: { flex: 1, }, buttonContainer: { flex: 1, flexDirection: 'row', backgroundColor: 'transparent', margin: 64, }, button: { flex: 1, alignSelf: 'flex-end', alignItems: 'center', }, text: { fontSize: 24, fontWeight: 'bold', color: 'white', }, });
内容的提问来源于stack exchange,提问作者Emmanuel John Navarro
相关产品推荐
相关产品推荐

