Search code examples
reactjsreact-hook-form

Get value of field before getting dirty in React Hook Form


I have profile component that takes some values from context and then edits them based on user interaction, when function editProfile is triggered after submitting the form, i check if the image has changed using the isDirty method, if so then i take the new image url and upload it to firebase, but i need to delete the previous image as it has been changed, how can i get the value of the previous image ?


import { useContext } from "react";
import AuthContext from "../../context/Auth-context/AuthContext";
import { useForm } from "react-hook-form";
import useFilePreview from "../Helpers/useFilePreview";
import { post } from "../Helpers/post";
import { uploadImageToFirebase } from "../Helpers/uploadImageToFirebase";


function Profile() {

  const { user } = useContext(AuthContext);
  const form = useForm({
    defaultValues: {... , image: user?.image}
  });
  const { register, handleSubmit, watch, getValues, formState: { dirtyFields } } = form;
  const image = watch("image");
  const imageToDelete = getValues("image");
  const [imagePreview] = useFilePreview(image);

  const editProfile = async (data) => {

    let url;
    if (dirtyFields.image) {
      url = await uploadImageToFirebase(data.image[0]);
    }
    data.image = url || image;

    post(`http://localhost:8000/api/edit-profile/${data.id}`, "PUT", {...data});

  };


  return <form onSubmit={handleSubmit(editProfile)}>
          <img src={imagePreview} />
          <label>Change profile picture</label>
          <input {...register("image")} type="file" accept="image/*" />
          <button>Save changes</button>
        </form>


}

export default Profile;

I tried to define a constant and store the previous image so i can delete it:

   const imageToDelete = getValues("image");

but this will give me the value of the new image as getValues("image") will also change, i need a way to grap the image value before getting dirty, how to achieve that ? thanks in advance


Solution

  • To track the previous profile image in your React component, use a state variable to store the initial image URL when the component mounts. This way, you can reference it later when you need to delete the old image.

    Here's the updated code:

    import { useContext, useEffect, useState } from "react";
    import AuthContext from "../../context/Auth-context/AuthContext";
    import { useForm } from "react-hook-form";
    import useFilePreview from "../Helpers/useFilePreview";
    import { post } from "../Helpers/post";
    import { uploadImageToFirebase } from "../Helpers/uploadImageToFirebase";
    
    function Profile() {
      const { user } = useContext(AuthContext);
      const [previousImage, setPreviousImage] = useState(user?.image);
    
      const form = useForm({
        defaultValues: { ... , image: user?.image }
      });
      const { register, handleSubmit, watch, formState: { dirtyFields } } = form;
      const image = watch("image");
      const [imagePreview] = useFilePreview(image);
    
      useEffect(() => {
        setPreviousImage(user?.image);
      }, [user]);
    
      const editProfile = async (data) => {
        let url;
    
        if (dirtyFields.image) {
          url = await uploadImageToFirebase(data.image[0]);
          if (previousImage) {
            // Call your function to delete the previous image from Firebase
            await deleteImageFromFirebase(previousImage);
          }
        }
    
        data.image = url || previousImage;
        await post(`http://localhost:8000/api/edit-profile/${data.id}`, "PUT", { ...data });
      };
    
      return (
        <form onSubmit={handleSubmit(editProfile)}>
          <img src={imagePreview} alt="Profile Preview" />
          <label>Change profile picture</label>
          <input {...register("image")} type="file" accept="image/*" />
          <button>Save changes</button>
        </form>
      );
    }
    
    export default Profile;