Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

File upload in react native expo project not working

I get No file uploaded as the response from the backend.

import ImagePicker from "expo-image-picker";
export const UpdateProfile = () => {
  const [address, setAddress] = useState("");
  const [formPostImg, setFormPostImg] = useState("");

  const [errMsg, setErrMsg] = useState<Record<string, string>>({
    profile: "",
  });

  const openImageLibraryKeyMessage = async () => {
    const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
    if (status !== "granted") {
      alert("Sorry, we need camera roll permissions to make this work!");
    }

    if (status === "granted") {
      const result = await ImagePicker.launchImageLibraryAsync({
        mediaTypes: ImagePicker.MediaTypeOptions.All,
        allowsEditing: true,
      });

      if (!result.canceled) {
        setFormPostImg(result.assets[0].uri);
        console.log({ formPostImg });
      }
    }
  };

  const handleUpdateProfile = async () => {
    console.log("clicked");
    console.log({ formPostImg });

    const formBody = new FormData();
    formBody.append("address", address);
    formBody.append("img", formPostImg);
    try {
      const res = await updateProfileFn({
        formBody,
        setErrMsg,
      });
      if (res && res.message.includes("success")) {
        console.log("success");
      }
    } catch (error) {
      // disable empty object error
    }
  };

  return (
    <SafeAreaView style={styles.mainBox}>
      {errMsg.profile && <Text>{errMsg.profile}</Text>}
      <View>
        <Text>Address</Text>
        <TextInput
          onChangeText={setAddress}
          value={address}
          placeholder="Enter address"
          style={styles.textInput}
        />
      </View>

      <Pressable onPress={openImageLibraryKeyMessage}>
        <Text>Pick image</Text>
      </Pressable>

      <Pressable onPress={handleUpdateProfile}>
        <Text>Update</Text>
      </Pressable>
    </SafeAreaView>
  );
};

I console.log({ formPostImg }); and get a response similar to

LOG  {"formPostImg": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Ffrontend-a5b88748-c8d6-412d-b8cc-ee88decfab14/ImagePicker/72bb7e65-9d16-4a78-a14e-009cd8cca53c.jpeg"}

which shows the image is being stored in state however when I try to upload, I get the error "No file uploaded" from the backend

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

This is the function I’m calling

async function updateProfileFn({
  formBody,
  setErrMsg,
}: {
  formBody: FormData;
  setErrMsg: React.Dispatch<React.SetStateAction<Record<string, string>>>;
}): Promise<ResSuccess | undefined> {
  const url = `${BASE_URL}/api/v1/users/updateProfile`;

  const token = await SecureStore.getItemAsync("token");
  console.log({ formBody });

  const res = await fetch(url, {
    method: "PATCH",
    headers: {
      "Content-Type": "multipart/form-data",
      Accept: "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: formBody,
  });

  if (!res.ok) {
    const exactErrorMsg = await res.json();
    const errorMsgString = JSON.stringify(exactErrorMsg);
    const errorMsg = JSON.parse(errorMsgString).error;

    // Set the error message in the state
    setErrMsg((prev) => ({ ...prev, profile: errorMsg }));

    // Throw an error to stop further execution
    return;
  }

  const data: ResSuccess = await res.json();

  console.log({ data });

  return data;
}
export default updateProfileFn;

This is the backend code for more context

export const updateProfile: express.RequestHandler = (
  req: Request,
  res: Response
) => {
  const { id: user_id } = getUserIDAndToken(req);

  if (!user_id) {
    res.status(401).json({ error: "Unauthorized" });
    return;
  }

  upload.single("img")(req, res, async (err) => {
    if (err) {
      if (err.message === "Unexpected field") {
        // console.log(error.message);

        res.status(400).json({ error: "Maximum of 1 image allowed" });
        return;
      }
    }

    const {
      address,
      phone_number,
      account_name,
      email,
      tag,
    }: {
      address: string;
      phone_number: string;
      account_name: string;
      email: string;
      tag: string;
    } = req.body;
    console.log({ address, phone_number, account_name, email, tag });

    // create uniqueIdentifier for the image
    const uniqueIdentifier = Date.now() + "-" + Math.round(Math.random() * 1e9);

    // create publicId for the image for cloudinary
    const publicId = `profile-img-${uniqueIdentifier}`;

    console.log(req.files);
    console.log(req.file?.path);

    if (!req.file) {
      res.status(400).json({ error: "No file uploaded" });
      return;
    }

    if (!address || !phone_number || !account_name || !email) {
      res.status(400).json({ error: "Missing required fields" });
      return;
    }

    try {
      const result = await cloudinary.uploader.upload(req.file.path, {
        public_id: publicId,
      });
      const imgURL = result.secure_url;
      console.log("imgURL", imgURL);

      pool.execute<ResultSetHeader>(
        `
                UPDATE users
                SET img = ?, address = ?, phone_number = ?, account_name = ?, email = ?, tag = ?
                WHERE id = ?
                `,
        [imgURL, address, phone_number, account_name, email, tag, user_id],
        (err) => {
          if (err) {
            console.error(err);
            res.status(500).json({ error: "Internal server error" });
            return;
          } else {
            console.log({ result });
            res.status(200).json({ message: "Profile updated successfully" });
          }
        }
      );
    } catch (error) {
      console.error(error);
      res.status(500).json({ error: "Internal server error" });
    }
  });
};

The log of these

console.log(req.files);
console.log(req.file?.path);

are both undefined

>Solution :

I think your issue might be your formData. I do this to upload an image using form data in react native:

      formData.append(
        `${image.name}`,      <=== Name of upload
        {
          uri: image.uri,
          name: image.name,
          type: 'image/jpeg',
        },                    <== Blob
        `${image.name}`       <=== FileName
      );

This is what worked for me so hopefully this is your issue as well!

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading