javascriptreact-nativeexpoimagepickerimageuri

How do I take an image uri from <ImagePickerExample.js> and use it in my <WritingPage.js> file?


My returns the following.

<View style={{photoBoxStyle}}>
      <TouchableOpacity onPress={pickImage} >
        {image && <Image source={{ uri: image }} style={{alignSelf: 'center',height:200, width:200, marginTop:10}}/>}
        {!image && (
          <Button title="Photo +" onPress={pickImage} />
        )}
      </TouchableOpacity>
</View>

In <WritingPage.js> file, I imported ImagePickerExample, and used it. I really want to get uri of the image that I selected inside ImagePickerExample, but the terminal log keeps telling me

LOG uri does not exist LOG post/49k8N1vrC2YDsHK5Vn2n7EEpkdG3/0.p60n27ciy4 LOG uploadImage tried LOG [TypeError: Network request failed]

What should I do? Please help...

<ImagePickerExample.js>

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

export default function ImagePickerExample(props) {
  const [image, setImage] = useState(null);
  const [showImagePicker, setShowImagePicker] = useState(false);
  const [photoBoxStyle, setPhotoBoxStyle] = useState({
    width:'90%',
    borderRadius: 10,
    borderColor: 'black',
    borderWidth: 1,
    alignSelf: 'center',
    marginTop: 10,
    height: 40,
  });
  useEffect(() => {
    if (image) {
      setPhotoBoxStyle({
        height: 220,
        width:'90%',
        borderRadius: 10,
        alignSelf: 'center',
      });
    } else {
      setPhotoBoxStyle({
        width:'90%',
        borderRadius: 10,
        alignSelf: 'center',
        marginTop: 10,
        height: 40,
      });
    }
  }, [image]);
  const pickImage = async () => {
    // No permissions request is necessary for launching the image library
    let result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true,
      aspect: [4, 3],
      quality: 1,
    });
    
    console.log(result);

    if (!result.canceled) {
      setImage(result.assets[0].uri);
      setShowImagePicker(true);
    }
  };

  return (
    <View style={{photoBoxStyle}}>
      <TouchableOpacity onPress={pickImage} >
        {image && <Image source={{ uri: image }} style={{alignSelf: 'center',height:200, width:200, marginTop:10}}/>}
        {!image && (
          <Button title="Photo +" onPress={pickImage} />
        )}
      </TouchableOpacity>
    </View>
  );
}

<WritingPage.js>

import {NavigationContainer, useNavigation} from "@react-navigation/native";
import Dell_fill from '../assets/icons/Dell_fill.png'
import Setting_fill from '../assets/icons/Setting_fill.png'
import Lock_fill from '../assets/icons/Lock_fill.png'
import Angry from '../assets/icons/Angry.png'
import Happy from '../assets/icons/Happy.png'
import Sad from '../assets/icons/Sad.png'
import Lol from '../assets/icons/Lol.png'
import Wow from '../assets/icons/Wow.png'
import ImagePickerExample from '../components/ImagePickerExample';
import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore';
import 'firebase/compat/storage'


//<Image source={{uri:props.route.params.image}}/> is used when I get the image source from the post screen.
function WritingPage(props){
  const navigation = useNavigation();
  const [content, setContent]=useState("")
  const [feeling, setFeeling]=useState("Happy")
  const [readableBy, setReadableBy]=useState("Friends")//should be changed to Myself
  const [activeIndex, setActiveIndex] = useState(2);
  const [selectedImage, setSelectedImage] = useState(null);

  const handleImagePress = (index) => {
    setActiveIndex(index);
    switch (index) {
      case 0:
        setFeeling('Sad');
        break;
      case 1:
        setFeeling('Wow');
        break;
      case 2:
        setFeeling('Happy');
        break;
      case 3:
        setFeeling('Lol');
        break;
      case 4:
        setFeeling('Angry');
        break;
    }
  };

  const handleImageSelected = (imageUri) => {
    console.log('imageUri:'+imageUri)
    setSelectedImage(imageUri);
  };
  
  const uploadImage =async() => {
    try{
      
      const uri = selectedImage;
      if(uri===null){
        console.log('uri does not exist');
      }else{
        console.log('uri does exist');
        console.log('uri:'+uri);
      }
      const childPath = `post/${firebase.auth().currentUser.uid}/${Math.random().toString(36)}`;
      console.log(childPath);
      console.log('uploadImage tried');
      const response = await fetch(uri);

      const blob = await response.blob();
      console.log('response, blob tried');
      //firebase storage에 저장하기
      const task = firebase.storage().ref().child(childPath).put(blob);

      const taskProgress = snapshot =>{
          console.log(`transferred: ${snapshot.bytesTransferred}`)
      }
      const taskCompleted = () =>{
          task.snapshot.ref.getDownloadURL().then((snapshot) => {
              savePostData(snapshot);
              console.log(snapshot);
          });
      }

      const taskError = snapshot =>{
          console.log(snapshot)
      }

      task.on("state_changed", taskProgress, taskError, taskCompleted)
  } catch (error) {
      console.log(error);
    }
  }
  const savePostData=(downloadURL)=>{
      //firestore에 저장하기
      firebase.firestore().collection('posts').doc(firebase.auth().currentUser.uid).collection("UserPosts")
      .add({
          downloadURL,
          content,
          creation: firebase.firestore.FieldValue.serverTimestamp(),
          feeling,
          readableBy
      }). then((function () {
        props.navigation.navigate('HomeScreen');
      }))
  }

    return(
      <View style={styles.container}>
        <ImageBackground source={m1}
          resizeMode="cover" style={styles.image}
        >
          <View style={styles.frame}>
            <Text style={styles.title}>오늘의 기억</Text>
            <TouchableOpacity onPress= {()=> navigation.navigate('HomeScreen')} style={styles.exitButton}>
                <Image source={Dell_fill} />
            </TouchableOpacity>
            <TouchableOpacity onPress= {()=> navigation.navigate('')} style={styles.button1}>
                <Image source={Setting_fill} />
            </TouchableOpacity>
            <TouchableOpacity onPress= {()=> navigation.navigate('')} style={styles.button2}>
                <Image source={Lock_fill} />
            </TouchableOpacity>
          </View>
          <View style={styles.frame2}>
            <Text style={styles.chooseText}>오늘의 표정을 선택해주세요</Text>
            <View style={styles.emoticonBox}>
                <TouchableOpacity style={styles.imageButton} onPress={()=>handleImagePress(0)}>
                    <Image source={Sad} style={[styles.margin,{tintColor: activeIndex === 0 ? 'red' : 'black'}]} />
                </TouchableOpacity>
                <TouchableOpacity style={styles.imageButton} onPress={()=>handleImagePress(1)}>
                    <Image source={Wow} style={[styles.margin,{tintColor: activeIndex === 1 ? 'red' : 'black'}]}/>
                </TouchableOpacity>
                <TouchableOpacity style={styles.imageButton} onPress={()=>handleImagePress(2)}>
                    <Image source={Happy} style={[styles.margin,{tintColor: activeIndex === 2 ? 'red' : 'black'}]}/>
                </TouchableOpacity>
                <TouchableOpacity style={styles.imageButton} onPress={()=>handleImagePress(3)}>
                    <Image source={Lol} style={[styles.margin,{tintColor: activeIndex === 3 ? 'red' : 'black'}]}/>
                </TouchableOpacity>
                <TouchableOpacity style={styles.imageButton} onPress={()=>handleImagePress(4)}>
                    <Image source={Angry} style={[styles.margin,{tintColor: activeIndex === 4 ? 'red' : 'black'}]}/>
                </TouchableOpacity>
            </View>
          </View>
          <View style={styles.frame3}>
            <View>
              <ImagePickerExample onImageSelected={handleImageSelected}/>
            </View>
            <View style={styles.dateBox}>
              <Text style={styles.date}>Date: ...</Text>
            </View>
            <TextInput
              placeholder="Write a Caption . . ."
              onChangeText={(content)=> setContent(content)}
              multiline={true}
            />
            <TouchableOpacity style={styles.buttonContainer} onPress={()=>uploadImage()}>
              <Text>Save</Text>
            </TouchableOpacity>
            
          </View>
        </ImageBackground>
      </View>
      // 로그인 페이지로 이동하는 버튼 
      //<Button title="go to main" onPress={()=>navigation.navigate('LogIn')}/>
    );
  };

  const styles = StyleSheet.create({
      buttonContainer:{
        backgroundColor:'white',
        alignItems: 'center',
      },
      container:{
        flex:1,
      },
      frame:{
        height: '100%',
        width: '100%',
        borderRadius: 40,
        backgroundColor: 'rgba(177,137,176,0.8)',
        justifyContent: 'center',
        alignItems: 'center',
        alignSelf: "center",  
        position: 'absolute',
        textAlign: 'center',
        flexDirection: 'column',
        flexWrap: 'wrap',
      },
      frame2:{
        height: '12%',
        width: '90%',
        borderRadius: 30,
        backgroundColor: '#E1BFDF',
        justifyContent: 'center',
        alignItems: 'center',
        alignSelf: "center",  
        position: 'absolute',
        textAlign: 'center',
        top: 70,
        marginBottom: 10,
      },
      emoticonBox:{
        flexDirection: 'row',
        justifyContent: 'space-between',
      },
      frame3:{
        height: '75%',
        width: '90%',
        borderRadius: 30,
        backgroundColor: '#E1BFDF',
        alignSelf: "center",  
        top: '9.4%',
        flexDirection: 'column',
      },
      photoBox:{
        height: 'auto',
        width:'90%',
        borderRadius: 10,
        borderColor: 'black',
        borderWidth: 1,
        alignSelf: 'center',
        marginTop: 10,
        minHeight: 40,
      },
      dateBox:{
        height: 25,
        width:'90%',
        borderRadius: 10,
        borderColor: 'red',
        borderWidth: 1,
        marginTop: 10,
        alignSelf: 'center',
      },
      image:{
        flex: 1,
        justifyContent: 'center',
      },
      title:{
        top:24,
        fontSize: 24,
        fontWeight: '400',
        position: "absolute",
        left: 30,
      },
      exitButton:{
        width: 50,
        height: 50,
        backgroundColor: '#A381A1',
        borderColor: '#6E8D9D',
        borderWidth: 2,
        justifyContent: 'center',
        alignItems: 'center',
        borderRadius: 50,
        top: 10,
        right: 10,
        position: 'absolute',
      },
      button1:{
        width: 50,
        height: 50,
        backgroundColor: '#A381A1',
        borderColor: '#6E8D9D',
        borderWidth: 2,
        justifyContent: 'center',
        alignItems: 'center',
        borderRadius: 50,
        top: 10,
        right: 70,
        position: 'absolute',
      },
      button2:{
        width: 50,
        height: 50,
        backgroundColor: '#A381A1',
        borderColor: '#6E8D9D',
        borderWidth: 2,
        justifyContent: 'center',
        alignItems: 'center',
        borderRadius: 50,
        top: 10,
        right: 130,
        position: 'absolute',
      },
      describingText:{
        top: '9%',
        fontSize: 24,
        fontWeight: '400',
        textAlign: 'center',
        position: "absolute",
      },
      inText: {
        fontSize: 24,
        fontWeight: '400',
      },
      margin: {
          margin: '2%',
      },
      imageButton:{
          backgroundColor:'',
          padding:10,
          alignItems: "center",
      },
      chooseText:{
          textAlign: 'center',
          top: '5%',
          fontSize: 24,
          fontWeight: '400',
      },
      date:{
          textAlign: 'left',
          left: '5%',
          top: '3%',
          fontSize: 14,
          fontWeight: '400'
      }
    });
  
  export default WritingPage;

Solution

  • Solution

    <ImagePickerExample.js>

    if (!result.canceled) {
      props.onImageSelected(result.assets[0].uri);
      setImage(result.assets[0].uri);
      setShowImagePicker(true);
    }
    

    Explanation

    Your two components WritingPage and ImagePickerExample need to be able to communicate with each other via props. Here's what you have already which helps you get achieve this (1 & 2), and the one final step that you are missing (3):

    1. ImagePickerExample is a child of WritingPage
    2. WritingPage tells the ImagePickerExample what to do when in gets an image. You defined a defining a handler function handleImageSelected and passed it down using a prop onImageSelected: <ImagePickerExample onImageSelected={handleImageSelected}/>. (parent => child)
    3. ImagePickerExample tells the WritingPage when it gets an image by calling the onImageSelected prop which was set by the parent. (child => parent)

    All that is left to do is to call props.onImageSelected with the uri (step 3). You'll do this in the ImagePickerExample component, inside the pickImage handler, once you've checked that you have a valid result.