0

In React-Native, I am creating a functional component called ImageSelector, in which I am using expo-image-picker and using the image URI as a required field in a parent component using Formik. My simulator works and I am able to successfully pick a generic image and log the image URI in the console ('success: ' + result.uri) but here are the following errors:

I want to display the image in the image component below but the image does not display (it does not break). I get the following error Unhandled promise rejection: ReferenceError: Can't find variable: props which I suppose is referring to the parent form component but I do not know what to change to get this error to go away.

Parent Component

import { View, Text, Button } from 'react-native';
import { Formik } from 'formik';
import * as yup from 'yup';
import ImageSelector from '../shared/imagePicker';

const newPostSchema = yup.object({
    image: yup.string()
        .required(),
})

export default function CreatePost({navigation}) {

    const setImageURI = (image) => {
        props.setFieldValue('imageUri', image.uri)
    }

    return (
        <View style={styles?.container}>
            <Formik
                initialValues={{
                    imageURI: null,
                }}
                validationSchema={newPostSchema}
                onSubmit={(values, actions) => {
                    console.log(values);
                    navigation.navigate('ReviewPost', {
                        imageURI: values.imageURI,
                    });
                }}
            >
            {props => (
                <View>
                    <ImageSelector
                        image={props.values.imageURI}
                        onImagePicked={setImageURI}
                    />
                    <Button onPress={props.handleSubmit} title='REVIEW' />

                </View>
            )}
            </Formik>
        </View>
    )
}

*** Nested ImageSelector Component in another file ***

import React, {useState, useEffect} from 'react';
import {View, Button, Image, StyleSheet} from 'react-native';
import * as ImagePicker from 'expo-image-picker';

const ImageSelector = ({image, onImagePicked}) => {

    const [selectedImage, setSelectedImage] = useState();

    useEffect(() => {
        if(image) {
            console.log('useEffect: ' + image);
            setSelectedImage({uri: image});
        }
    }, [image])

    pickImageHandler = async  () => {
        let result = await ImagePicker.launchImageLibraryAsync({
            title: 'Choose Image',
            maxWidth: 800,
            maxHeight: 600,
            mediaTypes: ImagePicker.MediaTypeOptions.All,
            allowsEditing: true,
            aspect: [4, 3],
            quality: 1
        });
        if (!result.cancelled) {
            console.log('success: ' + result.uri);
            onImagePicked({uri: result.uri});
            console.log('a');
            setSelectedImage({uri: result.uri});
            console.log('b');
        }
        if (result.cancelled) {
            console.log('result cancelled: ' + result.cancelled);
        }

    }

    return (
        <View style={styles.container}>
            <View style={styles.imageContainer}>
                <Image source={selectedImage} />
            </View>
            <View style={styles.button}>
                <Button title='Pick Image' onPress={this.pickImageHandler} />
            </View>
        </View>
    )
}

The following 4 lines do not execute (console logs are for testing to ensure they don't get called):

  • onImagePicked({uri: result.uri});*
  • console.log('a'); *
  • setSelectedImage({uri: result.uri});*
  • console.log('b');*

I need to get the props-related error to go away, set selectedImage to equal result.uri, and have the image display in the <Image /> component using selectedImage.uri as the image source.

Help?

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
Christian Z
  • 21
  • 2
  • 4

1 Answers1

1

The problem here is in the error message. Since you are creating a functional component called CreatePost, the typical syntax for passing props would be

export default function CreatePost(props) {
...
}

So your component can access the props that are passed down to it, such as setFieldValue, however, you have used the spread operator {navigation} instead of props, so you are already extracting all the props when you do that. Thus, the scope does not know of any props variable. So, for now, I would try changing the argument to this

export default function CreatePost(props) {
const { navigation } = props;
...
}

That way wherever else in the scope you have referenced props will still work and you will not lose access to the navigation property either, alternatively, you can simply change 'navigation.navigate' to 'props.navigation.navigate' also. So javascript is saying cant find variable props, because to it, this is just a simple vanilla javascript function, and it does not intuitively know of a variable called props, you have to explicitly call it that.

Also, I feel like there might still be issues in this part of the code

{props => (
                <View>
                    <ImageSelector
                        image={props.values.imageURI}
                        onImagePicked={setImageURI}
                    />
                    <Button onPress={props.handleSubmit} title='REVIEW' />

                </View>
            )}

So it would help if you could post the code where you are using your component, to see what props, such as setFieldValue, navigation etc.you are passing. You can just rewrite that part as

<Formik
   initialValues={{
      imageURI: null,
   }}
   validationSchema={newPostSchema}
   onSubmit={(values, actions) => {
      console.log(values);
      navigation.navigate('ReviewPost', {
        imageURI: values.imageURI,
      });
   }}
>
<View>
   <ImageSelector
     image={props.values.imageURI}
     onImagePicked={setImageURI}
   />
  <Button onPress={props.handleSubmit} title='REVIEW' />
</View>

Without doing the {props => part as with the refactor now you already have access to props in the scope.