How to correctly write FormData in my React app?


I have added a form in my app. When I send the form data to my local server I create an image with a title. When I attach images I should be using input type="file". Also, I should use FormData in my app.

But when I write my component I have an error 'formElem' is not defined in the two lines commented in the code. How do I fix it?

Here is my component code:

const AddImage = (props) => {
     formElem.onsubmit = async (e) => {         // ERROR THERE
       e.preventDefault();

          try {
              const response = await api(`${imageRoute}`, {
                  method:'POST',
                  body: new FormData(formElem),    // ERROR THERE
              }); 

          } catch(e) { 
              console.error(e);
          }   
    };

   return (

    <div className="formImage">

       <form id="formElem">
          <input type="text" name="name" value=""/>
          <input type="text" name="surname" value=""/>
          <input type="file" name="picture" accept="image/*"/>

        <div className="formButtonImage">
          <button type="submit">Add</button>
        </div>

       </form>
   </div>
   );
};

There is quite a lot of issues in your code but this should fix most of them:

import React, { useRef } from "react";

const AddImage = (props) => {
  const formRef = useRef();

  const handleSubmit = async (event) => {
    event.preventDefault();
    const data = new FormData(formRef.current);
    // Let's assume that api and imageRoute SOMEHOW exists
    try {
      const response = await api(imageRoute, {
        method: 'POST',
        body: data,    // ERROR THERE
      }); 
    } catch(e) { 
      console.error(e);
    }  
  };

  return (
    <div className="formImage">
      <form onSubmit={handleSubmit} ref={formRef}>
        <input type="text" name="name" />
        <input type="text" name="surname" />
        <input type="file" name="picture" accept="image/*" />

        <div className="formButtonImage">
          <button type="submit">Add</button>
        </div>
      </form>
    </div>
  );
}

Make sure you remove value="" from your form elements, otherwise React will treat them as controlled and you will not be able to actually write to them.


const AddImage = (props) => {
   const formEl = useRef(null)
   const onsubmit = () => {
       e.preventDefault();

      try {
          const response = await api(`${imageRoute}`, {
              method:'POST',
              body: new FormData(formEl.curent),    // ERROR THERE
          }); 

      } catch(e) { 
          console.error(e);
      }   
   }
   return (

    <div className="formImage">

       <form ref={formEl}onSubmit={onSubmit}>
          <input type="text" name="name" value=""/>
          <input type="text" name="surname" value=""/>
          <input type="file" name="picture" accept="image/*"/>

        <div className="formButtonImage">
          <button type="submit">Add</button>
        </div>

       </form>
   </div>
   );
};

But would be better to hang listener on did mount

const AddImage = (props) => {
       const formEl = useRef(null)
       useEffect(() => {
         formEl.current.addEventListener('submit', () => ...)
       }, [])

       return (

        <div className="formImage">

           <form ref={formEl}>
              <input type="text" name="name" value=""/>
              <input type="text" name="surname" value=""/>
              <input type="file" name="picture" accept="image/*"/>

            <div className="formButtonImage">
              <button type="submit">Add</button>
            </div>

           </form>
       </div>
       );
    };

Ideally, you must use onSubmit() event as <form id="formElem" onSubmit={handleSubmit}>.

If you want to continue your work, you can declare it as

const AddImage = (props) => {
     const formElem = document.querySelector('#formElem');

     formElem.onsubmit = async (e) => {         // ERROR THERE
       e.preventDefault();
       // REST OF THE CODE
          try {

          }
     }
}