skip to Main Content

How to modify the code so that after submitting the image changes to base64 code and so that I can use the formData from the form in the subpage component.

At the moment the AddForm look like this:

import { Form, useNavigation } from 'react-router-dom';
import classes from './AuthForm.module.css';

function AddForm() {
  const navigation = useNavigation() 
  const isSubmitting =navigation.state === 'submitting'

  function fileToBase64(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(file);
  
      reader.onload = () => {
        const base64 = reader.result;
        resolve(base64);
      };
  
      reader.onerror = (error) => {
        reject(error);
      };
    });
  }

  function handleFileInputChange(event) {
    const file = event.target.files[0];
  
    fileToBase64(file)
      .then((base64) => {
        console.log(base64);
      })
      .catch((error) => {
        console.error(error);
      });
  }
  
  return (
    <>
      <Form method="post" className={classes.form}>
      <div>
        <label htmlFor="title">Tytuł:</label>
        <input
          type="text"
          id="title"
          name='title'
        />
      </div>
      <div>
        <label htmlFor="file">Wybierz plik:</label>
        <input
          type="file"
          id="file"
          name='title'
          onChange={handleFileInputChange}
        />
      </div>
      <button disabled={isSubmitting}>{isSubmitting ? 'Adding...' : 'Add'}</button>
      </Form>
      </>
  );
}

export default AddForm;

And component where I use it look like this:

import AddForm from '../components/AddForm';

function AddPage() {
  return <AddForm/>; 
}

export default AddPage;

export async function action({ request }) { 
  const data = await request.formData();
  console.log(data)
  const postData = { 
    titlt: data.get('title'),
    file: data.get('file'),
  };
  console.log(postData)
}

I already tried to modify data in the next component but the file field in formData was null.

2

Answers


  1. You add form data like this.

    let formData = new FormData();
    formData.append('title', title);
    formData.append('body', body);
    formData.append('image', image);
    

    Then make request like this,

    axios({
      method: "post",
      url: "myurl",
      data: formData,
      headers: { "Content-Type": "multipart/form-data" },
    })
    .then(function (response) {
        console.log(response);
    })
    .catch(function (response) {
        console.log(response);
    });
    

    I am showing example with axios, as it is my goto. You can do this with any request library.

    Login or Signup to reply.
  2. It seems the problem is that you have an onChange handler in the component that takes the input’s value and converts it to a base64 value but then doesn’t do anything with it, meanwhile, the route’s action function only reads/accesses the form fields’ current values, which will only be the file name.

    Add some state to store the base64 converted file string and add a hidden field to the form to hold this value. The action function can access this field value.

    You also had a typo in the file input where the input had the same name attribute as the title input.

    Example:

    function AddForm() {
      const navigation = useNavigation();
      const isSubmitting = navigation.state === "submitting";
    
      const [base64File, setBase64File] = useState(""); // <-- local state
    
      function fileToBase64(file) {
        return new Promise((resolve, reject) => {
          const reader = new FileReader();
          reader.readAsDataURL(file);
    
          reader.onload = () => {
            const base64 = reader.result;
            resolve(base64);
          };
    
          reader.onerror = (error) => {
            reject(error);
          };
        });
      }
    
      function handleFileInputChange(event) {
        const file = event.target.files[0];
    
        fileToBase64(file)
          .then((base64) => {
            console.log(base64);
            setBase64File(base64); // <-- update local state
          })
          .catch((error) => {
            console.error(error);
          });
      }
    
      return (
        <Form method="post" className={classes.form}>
          <div>
            <label htmlFor="title">Tytuł:</label>
            <input type="text" id="title" name="title" />
          </div>
          <div>
            <label htmlFor="file">Wybierz plik:</label>
            <input
              type="file"
              id="file"
              name="file" // <-- fix typo
              onChange={handleFileInputChange}
            />
          </div>
          <input
            name="base64File"
            value={base64File} // <-- set input's value
            hidden
            readyOnly
          />
          <button disabled={isSubmitting}>
            {isSubmitting ? "Adding..." : "Add"}
          </button>
        </Form>
      );
    }
    
    export async function action({ request }) {
      const data = await request.formData();
      console.log(data);
    
      const title = data.get("title");
      const file = data.get("base64File");
    
      const postData = {
        title,
        file
      };
      console.log(postData);
    
      ... business logic
    
      ... return response?
    }
    

    Demo

    Edit how-can-i-modify-formdata-before-sending-it

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search