4

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>
        );
    }
}

1 Answer 1

9

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.