Загрузка файла в действии: невозможно передать данные файла в бэкэнд с другими полями формы. Видя неопределенное в государстве - PullRequest
0 голосов
/ 22 марта 2020

Я создаю приложение для рецептов и в настоящее время работаю над тем, чтобы пользователь мог загружать свои собственные рецепты. У меня есть форма с различными полями ввода, и одним из них является загрузка изображений. Вот как моя форма выглядит в методе render ():

render()   {
        return <div>
            <h2>
                Share Your Culinary Art
            </h2>
            <form method="post" onSubmit = {
                e =>  this.submitRecipe(e) 
            }>
                <div>
                    <label htmlFor="name">Recipe Name *</label>
                    <input name="name" onInput = { e => { this.handleChange(e)}} required />
                </div>
                <div>
                    <label htmlFor="cuisine">Cuisine</label>
                    <input name="cuisine" onInput = { e => { this.handleChange(e)}}/>
                </div>
                <div>
                    <label htmlFor="ingredients" required>Ingredients*</label> <br />
                    <textarea name="ingredients" rows='10' columns='30' placeholder="Ingredients separated by commas" onInput = { e => { this.handleChange(e)}}/>
                </div>
                <div>
                    <label htmlFor="instructions">Instructions *</label> <br />
                    <textarea name="instructions" rows='10' columns='30' onInput = { e => { this.handleChange(e)}} required/>
                </div>
                <div>
                    <label htmlFor="image">Choose your recipe image:</label>
                    <!-- below is problematic area-->
                    <input type="file" name="file" onChange= { e => {this.onChangeImageHandler(e)} } />
                </div>
                <button>Reset</button>
                <button>Upload</button>
            </form>
        </div>
    }

Все поля ввода (кроме файла один) присоединены к функции handleChange (), которая, в свою очередь, вызывает функцию handleInputChange (), которая выглядит следующим образом в том же файле:

handleChange = e => {
        e.preventDefault();
        this.handleInputChange(e.target.name, e.target.value);
    }

    handleInputChange = (key, value) => {

        this.setState({
            uploadRecipesFormData: {
                _id: uuidv4(),
                ...this.state.uploadRecipesFormData,
                addedBy: 'guest',
                [key]: value
            }
        });
    }

Вместо этого загрузка изображения присоединяется к функции onChangeImageHandler:

onChangeImageHandler = e => {
        this.setState({
            selectedFile: e.target.files[0]
        });
    }

Когда пользователь нажимает кнопку «Загрузить», запускается функция submitRecipe, которая затем запускает функцию uploadRecipe. Оба определены ниже:

submitRecipe = e => {
        e.preventDefault();
        this.uploadRecipe();
    }

uploadRecipe = () => {
        console.log(this.state.selectedFile);
        const imageData = new FormData();
        imageData.append('file', this.state.selectedFile);
        this.setState({
            uploadRecipesFormData : {
                ...this.state.uploadRecipesFormData,
                imageData
            }
        })
        axios.post(`http://localhost:3000/recipes`, this.state.uploadRecipesFormData)
             .then(res => alert(res.data))
             .catch(err => console.error(err));
    }

Для полноты картины весь файл показан ниже:

import React from 'react';
import axios from 'axios';
import { v4 as uuidv4 } from 'uuid';

export default class UploadRecipes extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            uploadRecipesFormData: {},
            selectedFile: null
        };
    }

    uploadRecipe = () => {
        console.log(this.state.selectedFile);
        const imageData = new FormData();
        imageData.append('file', this.state.selectedFile);
        this.setState({
            uploadRecipesFormData : {
                ...this.state.uploadRecipesFormData,
                imageData
            }
        })
        axios.post(`http://localhost:3000/recipes`, this.state.uploadRecipesFormData)
             .then(res => alert(res.data))
             .catch(err => console.error(err));
    }

    onChangeImageHandler = e => {
        this.setState({
            selectedFile: e.target.files[0]
        });
    }

    handleChange = e => {
        e.preventDefault();
        this.handleInputChange(e.target.name, e.target.value);
    }

    handleInputChange = (key, value) => {

        this.setState({
            uploadRecipesFormData: {
                _id: uuidv4(),
                ...this.state.uploadRecipesFormData,
                addedBy: 'guest',
                [key]: value
            }
        });
    }

    submitRecipe = e => {
        e.preventDefault();
        this.uploadRecipe();
    }

    render()   {
        return <div>
            <h2>
                Share Your Culinary Art
            </h2>
            <form method="post" onSubmit = {
                e =>  this.submitRecipe(e) 
            }>
                <div>
                    <label htmlFor="name">Recipe Name *</label>
                    <input name="name" onInput = { e => { this.handleChange(e)}} required />
                </div>
                <div>
                    <label htmlFor="cuisine">Cuisine</label>
                    <input name="cuisine" onInput = { e => { this.handleChange(e)}}/>
                </div>
                <div>
                    <label htmlFor="ingredients" required>Ingredients*</label> <br />
                    <textarea name="ingredients" rows='10' columns='30' placeholder="Ingredients separated by commas" onInput = { e => { this.handleChange(e)}}/>
                </div>
                <div>
                    <label htmlFor="instructions">Instructions *</label> <br />
                    <textarea name="instructions" rows='10' columns='30' onInput = { e => { this.handleChange(e)}} required/>
                </div>
                <div>
                    <label htmlFor="image">Choose your recipe image:</label>
                    <input type="file" name="file" onChange= { e => {this.onChangeImageHandler(e)} } />
                </div>
                <button>Reset</button>
                <button>Upload</button>
            </form>
        </div>
    }
}

Проблема, с которой я сталкиваюсь, заключается в том, что мой переданный файл не отображается должным образом в инструментах React dev: enter image description here

И когда я проверяю журнал консоли непосредственно перед запуском загрузки, где я использую FormData для прикрепления файла, я вижу, что он регистрируется:


    File {name: "chicken-curry.jpg", lastModified: 1584878531812, lastModifiedDate: Sun Mar 22 2020 08:02:11 GMT-0400 (Eastern Daylight Time), webkitRelativePath: "", size: 344292, …}
    name: "chicken-curry.jpg"
    lastModified: 1584878531812
    lastModifiedDate: Sun Mar 22 2020 08:02:11 GMT-0400 (Eastern Daylight Time) {}
    webkitRelativePath: ""
    size: 344292
    type: "image/jpeg"
    __proto__: File

Однако в отправляемых заголовках запроса я не вижу атрибута файла или каких-либо данных, указывающих c на файл: enter image description here

Я просто не могу понять как я должен передавать данные этого файла вместе с другими полями.

...