Upload files to ImageKit using React-Native, and Node.js

LexyLexy
4 min read

This guide assumes that you have some familiarity with setting up Node.js and React Native projects. It's not specifically tailored for absolute beginners who are new to these technologies. If you already have a basic project setup, you're good to go!

The following code snippet is more of a pseudo-code format, providing a general outline of the process. We'll be utilizing the Expo ImagePicker module to enable users to select images from their device's photo library.

Feel free to follow along and adapt the code to suit your project's needs. Let's get started!


Expo/React Native Code

When the user clicks the "Upload Image" button, the pickImage function is called. This function uses the launchImageLibraryAsync method of the ImagePicker module to open the image library and let the user select an image. The allowsEditing option is set to true, which means the user can edit the image before selecting it.

After the user selects an image, the image's URI is stored in the state using the setImage function.

The handleUpdatePersonalInformation function is called when the user wants to upload the selected image to the server. This function creates a FormData object and appends the selected image to it. The uri of the image is then split to remove the "file:/" prefix.

Finally, the fetch function is used to send the FormData object to the server. The server should return a response containing the URL of the uploaded image. In this case, we're just showing a Toast message saying "Uploaded Image to ImageKit!" when the image is successfully uploaded.

In the JSX code, the selected image is displayed in an Image component, and the user can click the "Upload Image" button to open the image library and select an image.

Remember to replace the "YOUR SERVER URL" placeholder with the actual URL of your server.

import * as ImagePicker from "expo-image-picker";

const [image, setImage] = useState(null);

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,
  });

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

const handleUpdatePersonalInformation = () => {
  const formData = new FormData();
  const filePath = image.split("file:/").join("");
  formData.append("profilePicture", {
    uri: filePath,
    type: "image/jpeg",
    name: "profile-picture.jpg",
  });

  fetch(`YOUR SERVER URL`, {
    method: "PATCH",
    body: formData,
  })
    .then((res) => Toast("Uploaded Image to ImageKit!"))
    .catch((err) => console.log(err));
};

return (
  <SafeAreaView style={styles.container}>
    <View style={{ flexDirection: "row", alignItems: "center", gap: 8 }}>
      <Image
        source={{
          uri: image
            ? image
            : "https://ik.imagekit.io/13x54r/I%20Send%20Money/Screenshot%202023-11-23%20063405.png?updatedAt=1700739253715",
        }}
        style={{ width: 55, height: 55 }}
      />
      <TouchableOpacity onPress={pickImage}>
        <Text
          style={{
            fontWeight: 600,
            padding: 5,
            backgroundColor: "#0001",
          }}
        >
          Upload Image
        </Text>
      </TouchableOpacity>
    </View>
  </SafeAreaView>
);

Node.js Code

In the provided code, a multer middleware is used to handle the image uploads in a Node.js server. Multer is a popular middleware for handling multipart/form-data.

First, a disk storage is created to store the uploaded images. The storage destination is set to "uploads/", and the filename function generates a unique name for the uploaded file based on the current date and time.

Next, multer is initialized with the disk storage.

Then, the ImageKit SDK is used to upload the image to the ImageKit server. ImageKit is a powerful media API that can be used to handle, store, and serve images.

After uploading the image, the server updates the user's profile information with the new photo URL and returns a response to the client.

Lastly, the client's code for the mobile application is also included. The mobile application allows users to upload their profile picture using the expo-image-picker package. The uploaded image is then sent to the server using a PATCH request.

This approach ensures that the uploaded image is stored securely and efficiently.

const multer = require("multer");
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, "uploads/");
  },
  filename: function (req, file, cb) {
    let extArray = file.mimetype.split("/");
    let extension = extArray[extArray.length - 1];
    const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
    cb(null, file.fieldname + "-" + uniqueSuffix + "." + extension);
  },
});

const upload = multer({ storage: storage });

var ImageKit = require("imagekit");

var imagekit = new ImageKit({
  publicKey: "",
  privateKey: "",
  urlEndpoint: "",
});

const fs = require("fs");

Router.patch(
  "/:userUid",
  upload.single("profilePicture"),
  async (req, res) => {
    try {
      const profile = await ProfileInformation.findOne({
        userUid: req.params.userUid,
      });
      if (!profile) {
        return res.status(404).json({ message: "Profile not found" });
      }

      if (req.file) {
        const data = await new Promise((resolve, reject) => {
          fs.readFile(req.file.path, (err, data) => {
            if (err) reject(err);
            else resolve(data);
          });
        });

        const imagekitResponse = await new Promise((resolve, reject) => {
          imagekit.upload(
            {
              file: data,
              fileName: req.file.filename,
            },
            (error, result) => {
              if (error) reject(error);
              else resolve(result);
            }
          );
        });

        profile.photoUrl = imagekitResponse.url;
        fs.unlinkSync(req.file.path);
      }

      const updatedProfile = await profile.save();
      res.status(200).json(updatedProfile);
    } catch (err) {
      res.status(500).json({ error: err });
    }
  }
);

If you're looking for a solution where images are stored on a server like Heroku, which has a refreshing dyno that may lead to file deletion, then this is the right approach for you. Why choose ImageKit over options like AWS Bucket or Firestore? The answer is simple: ImageKit is a free option. Happy hacking!

0
Subscribe to my newsletter

Read articles from Lexy directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Lexy
Lexy

Building a more open web, one block at a time. ๐Ÿ“œ