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

Expo路由传参:如何从props获取指定单值?

问题解决:React Navigation传递参数后访问子属性报错"undefined is not an object"

问题本质

报错核心是组件首次渲染时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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 12:03:14