How to upload files to S3 with Expo
This is a practical example of how to upload files to S3 with Expo.
Previous requirements
Make sure you have Node.js and npm installed on your system. You can verify its installation by running the following commands in your terminal:
node -v
npm -v
If you don’t have Node.js and npm installed, you can download and install them from nodejs.org.
Create a new Expo project
npx create-expo-app@latest upload-files-s3-expo
Install dependencies
npm i
Create a page to upload files
import { View, Text } from "react-native";
const UploadFiles = () => {
return (
<View>
<Text>upload-files</Text>
</View>
);
};
export default UploadFiles;
Now create a logic to upload files install expo-document-picker or expo-image-picker
npx expo install expo-document-picker
Or
npx expo install expo-image-picker
Upload files from the device
—With expo-document-picker—
const [image, setImage] = React.useState<DocumentPicker.DocumentPickerResult>();
const handlePickPhoto = async () => {
const result = await DocumentPicker.getDocumentAsync({
type: "image/png",
copyToCacheDirectory: true,
});
if (result) {
setImage(result);
}
};
We created a function to open files, applied a filter to allow only PNG images to be uploaded, and stored the result in the image
state.
Configure polyfills
Currently, uploading files from React Native with Expo presents several compatibility issues with blobs and random values. To address these problems, we installed the following packages:
react-native-url-polyfill
react-native-get-random-values
web-streams-polyfill@3.3.3
react-native-polyfill-globals
npx expo install react-native-url-polyfill react-native-get-random-values web-streams-polyfill@3.3.3 react-native-polyfill-globals
Now, in the _layout.tsx
file, which serves as our entry point, we import the polyfills.
import 'react-native-url-polyfill/auto'
import 'react-native-get-random-values'
import 'web-streams-polyfill/ponyfill'
import 'react-native-polyfill-globals'
global.crypto.getRandomValues;
global.Buffer = Buffer;
global.ReadableStream = ReadableStream as any
With these imports, we now have compatibility with additional functionalities.
Configure AWS Client
import { S3 } from "@aws-sdk/client-s3";
export const s3Client = new S3({
forcePathStyle: false,
endpoint: //S3_ENDPOINT,
region: //S3_REGION,
credentials: {
accessKeyId: //S3_ACCESS_KEY_ID,
secretAccessKey: //S3_SECRET_ACCESS_KEY,
},
});
Upload files to S3
We import our S3 client and configure our function to upload files.
import { s3Client } from "@/plugins/aws-s3";
const UploadFiles = () => {
const [image, setImage] = React.useState<DocumentPicker.DocumentPickerResult>();
---
//rest of the code
---
const handleUploadFile = async () => {
if (image && image.assets && image.assets.length > 0) {
//Fetch the image from the device and convert it to a blob
const blob_data = await fetch(image.assets[0].uri);
const blob = await blob_data.blob();
let URL = //Name of the file with the path example: "logo/1234567890/1234567890/logo.png"
try {
const jsonUploadParams = {
Bucket: //S3_BUCKET,
Key: URL,
Body: blob,
ContentType: "image/png",
};
return await s3Client
.putObject(jsonUploadParams)
.then(() => {
//Success message
return URL;
})
.catch(() => {
//Error message
return "";
});
} catch {
//Error message
return "";
}
}
return "";
};
return ()
}
Conclusion
In conclusion, by addressing compatibility issues and configuring the necessary tools, we successfully set up a seamless file upload process in our React Native project. These steps ensure better functionality and integration with external services like S3.
Thank you for following along, and happy coding! 🚀