Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uploading image with form data in React

I am trying to upload a photo in my React application, along with some form data. It works with uploading form data from ItemAdd.jsx, a child component of ItemList.jsx. However, when I try to also POST an image file with this data, the image property is undefined when it hits the server. My suspicion is that I'm using the wrong content-type in the request, but I'm not sure what I should be using instead (if that is the issue here).

Parent Component - ItemList.jsx

import React from 'react';
import 'whatwg-fetch';
import classNames from 'classnames';
import ItemAdd from './ItemAdd.jsx';

export default class ItemList extends React.Component {
    constructor() {
        super();
        this.createItem = this.createItem.bind(this);
    }

    createItem(newItem) {
        console.log('PHOTO:', newItem.image);
        fetch('/api/item', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(newItem),
        }).then(response => {
        }).catch(err => {
        });
    }

    render() {
        return (
            <div>
                <ItemAdd createItem={this.createItem} />
            </div>
        );
    }
}

Child Component - ItemAdd.jsx

import React from 'react';

export default class ItemAdd extends React.Component {

    constructor() {
        super();
        this.handleSubmit = this.handleSubmit.bind(this);
        this.state = {
            image: null,
            imagePreviewUrl: null
        }
    }

    handleSubmit(e) {
        e.preventDefault();
        let form = document.forms.itemAdd;
        this.props.createItem({
            name: form.name.value,
            image: this.state.image
        });
        // Clear the form and state for the next input.
        form.name.value = "";
        this.state.image = null;
        this.state.imagePreviewUrl = null;
    }

    handleImageChange(e) {
        e.preventDefault();

        let reader = new FileReader();
        let file = e.target.files[0];

        reader.onloadend = () => {
            this.setState({
                image: file,
                imagePreviewUrl: reader.result
            });
        }

        reader.readAsDataURL(file)
    }

    render() {
        let { imagePreviewUrl } = this.state;
        let $imagePreview = null;
        if (imagePreviewUrl) {
            $imagePreview = (<img src={imagePreviewUrl} className={'img-preview'} />);
        } else {
            $imagePreview = (<div className="previewText">Please select an image.</div>);
        }
        return (
            <div>
                <form name="itemAdd" onSubmit={this.handleSubmit}>
                    <table>
                        <tr>
                            <td><label for="name">Name:</label></td>
                            <td><input type="text" name="name" id="name" placeholder="Name" /></td>
                        </tr>
                        <tr>
                            <td><input type="file" onChange={(e) => this.handleImageChange(e)} /></td>
                            <td>
                                <div className="img-preview">
                                    {$imagePreview}
                                </div>
                            </td>
                        </tr>
                        <tr>
                            <td><button>Add</button></td>
                        </tr>
                    </table>
                </form>
            </div>
        );
    }
}
like image 202
petehallw Avatar asked Mar 07 '23 14:03

petehallw


1 Answers

You might not be able to post an image as part of JSON data, calling JSON.stringify() on an image is not a good idea.

I would recommend using formData to submit the form, which makes it multipart/form-data content type. You might have to handle that differently in the backend.

Example :

createItem(newItem) {
    console.log('PHOTO:', newItem.image);
    const h = {}; //headers
    let data = new FormData();
    data.append('image', newItem.image);
    data.append('name', newItem.name);
    h.Accept = 'application/json'; //if you expect JSON response
    fetch('/api/item', {
      method: 'POST',
      headers: h,
      body: data
    }).then(response => {
        // TODO : Do something
    }).catch(err => {
        // TODO : Do something
    });
  }

You can read more on formData

like image 128
Ankari Avatar answered Mar 31 '23 10:03

Ankari