Uploading image or other files using React Native and Laravel

Many of us struggle coding upload files or photo features during React Native App development process. In this article, I will show you simple process to upload file with react native app and laravel backend. I will be using Expo framework of react native to keep things simple. If you are new to expo go through the documentation before starting with this tutorial.

First Lets install expo command line tool and create/ initialize a react native project using below commands.

npm install --global expo-cli

expo init fileupload-app

When you initialise project you will get four different templates to choose from. The four options will be blank, blank (TypeScript), tabs (TypeScript), minimal and minimal (TypeScript). We will be using blank (TypeScript).

Now we need to install  file picker and image picker, two dependencies for our project. Installation of these dependencies are very simple, since, we are using expo framework of react native. Run below commands to install the dependencies.

expo install expo-document-picker

expo install expo-image-picker

Next, replace the code in App.tsx with the code below :

import React, { useState, useEffect } from 'react';
import { Button, Image, View, Platform, Text } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import * as DocumentPicker from 'expo-document-picker';
import Constants from 'expo-constants';

export default function DocumentPickerExample() {
  const [file, setFile] = useState(null);
  const [image, setImage] = useState(null);
  const [uploading, startUploading] = useState(false);
  const YOUR_SERVER_URL = "https://ennysl368sf4new.m.pipedream.net";
  useEffect(() => {
    (async () => {
      if (Platform.OS !== 'web') {
        const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
        if (status !== 'granted') {
          alert('Sorry, we need camera roll permissions to make this work!');
        }
      }
    })();
  }, []);
  const getMimeType = (ext) => {
    // mime type mapping for few of the sample file types
    switch (ext) {
      case 'pdf': return 'application/pdf';
      case 'jpg': return 'image/jpeg';
      case 'jpeg': return 'image/jpeg';
      case 'png': return 'image/png';
    }
  }
  const pickImage = async () => {
    let result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true,
      aspect: [4, 3],
      quality: 1,
    });

    console.log(result);

    if (!result.cancelled) {
      setImage(result.uri);
    }
  };
  const pickFile = async () => {
    let result = await DocumentPicker.getDocumentAsync({
      type: '*/*'
    });

    console.log(result);

    if (!result.cancelled) {
      setFile(result.uri);
    }
  };
  const uploadFile = async () => {
    if(file||image){
      const fileUri = file ? file : image;
      let filename = fileUri.split('/').pop();

      const extArr = /\.(\w+)$/.exec(filename);
      const type = getMimeType(extArr[1]);
      setImage(null);
      setFile(null);
      startUploading(true);

      let formData = new FormData();

      formData.append('filetoupload', { uri: fileUri, name: filename, type });

      const response = await fetch(YOUR_SERVER_URL, {
        method: 'POST',
        body: formData,
        headers: {
          'content-type': 'multipart/form-data',
        },
      });
      startUploading(false);
      const responseAgain = await response.text();
      console.log(responseAgain);
      return response;
    }
};

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button title="Pick a Photo from mobile" onPress={pickImage} />
      {image && <Image source={{ uri: image }} style={{ width: 200, height: 200 }} />}
      <View style={{ height: 50 }}/>
      <Button title="Pick a file from mobile" onPress={pickFile} />
      <View style={{ height: 50 }}/>
      { uploading ? <Text>Uploading</Text> :
      <Button title="Upload" onPress={uploadFile} /> }
    </View>
  );
}

In the above code, We are using Image picker to pick photo from gallery or Document picker to pick document from Files section of mobile. On clicking the upload button the file is sent to Laravel server using javascript FormData api.

Now lets code the Laravel Server. First we will create a route in routes/api.php by adding below code.

Route::any('/','FileController@uploadfile');

Finally, we will create a FileController.php in app/Http/Controllers directory and add the action below :

public function uploadfile(Request $request){

        if($request->has('filetoupload')){
          $file = $request->file('filetoupload');
          $exte = $file->extension();
          $newFileName = substr(md5(mt_rand()), 0, 7);
          $path = $file->storeAs('public',$newFileName.".".$exte);

          return response()->json(['path' => $path]);
         }else{
           return response()->json(['path' => null]);
         }
}

In the above code, if request has a file then we are getting the file and its extensions. We are generating a random file name and storing the file with the new file name and its original extension. If everything goes well, we are returning the file path else we return null as path.