Как передать изображение в бэкэнд от реакции и редукции - PullRequest
0 голосов
/ 27 декабря 2018

Я использую стек MERN и хочу иметь возможность загрузить изображение во внешний интерфейс (реагировать) и получить доступ к нему в серверном (экспресс, nodejs), чтобы сохранить его позже.Я использую multer, но продолжаю получать неопределенность при попытке console.log () req.file объект.

внешний интерфейс:

import React, { Component } from "react";
import { Link, withRouter } from "react-router-dom";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { addPlayer } from "../../actions/profileActions";

class AddPlayer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      avatarFile: null,
      name: "",
      age: "",
      apodo: "",
      captain: false,
      description: "",
      atributes: "",
      facebook: "",
      instagram: "",
      twitter: "",
      youtube: "",
    };
    this.onSubmit = this.onSubmit.bind(this);
    this.onImageChange = this.onImageChange.bind(this);
  }

  onSubmit(e) {
    e.preventDefault();

    const playerData = {
      name: this.state.name,
      age: this.state.age,
      apodo: this.state.apodo,
      captain: this.state.captain,
      description: this.state.description,
      atributes: this.state.atributes,
      facebook: this.state.facebook,
      instagram: this.state.instagram,
      twitter: this.state.twitter,
      youtube: this.state.youtube
    };

    this.props.addPlayer(playerData, this.props.history);
  }

  onImageChange(event) {
    if (event.target.files && event.target.files[0]) {
      this.setState({ avatarFile: event.target.files[0] });
    }
  }

  render() {
    return(
      <div>
        <form
          onSubmit={this.onSubmit}
          method="POST"
          encType="multipart/form-data"
        >
          <div className="text-center mb-3">
            <input
              type="file"
              name="file"
              id="file"
              accept="image/*"
              className="inputfile"
              onChange={this.onImageChange}
             />
             <label htmlFor="file" className="btn btn-primary">
               Elegir foto
             </label>
            </div>
        </form>
      </div>
    );
  }

}

AddPlayer.propTypes = {
  addPlayer: PropTypes.func.isRequired,
  profile: PropTypes.object.isRequired,
  errors: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  profile: state.profile,
  errors: state.errors
});

export default connect(
  mapStateToProps,
  { addPlayer }
)(withRouter(AddPlayer));

Действие AddPlayer

//Create player
export const addPlayer = (playerData, history) => dispatch => {
  axios
    .post("api/profile/player", playerData)
    .then(res => history.push("/dashboard"))
    .catch(err =>
      dispatch({
        type: GET_ERRORS,
        payload: err.response.data
      })
    );
};

просто публикует данные игрока и затем перенаправляет его на другой компонент.

бэкэнд разделен на два файла. server.js , где установлены все промежуточные программы, и profile.js , который содержит все маршруты.

сервер сервер.js

const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const passport = require("passport");
const cors = require("cors");

const users = require("./routes/api/users");
const profile = require("./routes/api/profile");
const matches = require("./routes/api/matches");

const app = express();

//body-parser middleware
app.use(bodyParser.urlencoded({ extended: false, limit: "50mb" }));
app.use(bodyParser.json({ limit: "50mb" }));

//db config
const db = require("./config/keys").mongoURI;

//cors
app.use(cors());

//connect to mongoose
mongoose
  .connect(
    db,
    { useNewUrlParser: true }
  )
  .then(() => console.log("MongoDB connected"))
  .catch(err => console.log(err));

//Passport middleware
app.use(passport.initialize());

//Passport config
require("./config/passport")(passport);

app.use("/api/profile", profile);

const port = process.env.PORT || 5000;

app.listen(port, () => console.log(`server running on port ${port}`));

profile.js

const express = require("express");
const router = express.Router();
const passport = require("passport");
const multer = require("multer");

const parser = multer({ dest: "./images" });

router.post(
  "/player",
  [passport.authenticate("jwt", { session: false }), parser.single("file")],
  (req, res) => {

const newPlayer = {
  name: req.body.name,
  age: req.body.age,
  apodo: req.body.apodo,
  description: req.body.description,
  captain: req.body.captain,
  social: {
    instagram: req.body.instagram,
    facebook: req.body.facebook,
    twitter: req.body.twitter,
    youtube: req.body.youtube
  }
};
//set the Avatar for the player
console.log(req.file);
});

Буду признателен за любую помощь.Спасибо.

1 Ответ

0 голосов
/ 28 декабря 2018

Похоже, у вас есть две проблемы:

  1. Вы не используете правильный тип контента (axios по умолчанию предполагает application/json и вам нужно multipart/form-data)
  2. Похоже, вы предполагаете, что загрузка будет работать только потому, что она является частью формы, когда вы переопределяете onSubmit и вызываете e.preventDefault(), вы отменяете любое поведение браузера по умолчанию для этой формы и должны вручную загрузить файл на сервер (Я не вижу ничего подобного в вашем текущем коде.)

Для того, чтобы эта работа работала, должно произойти несколько изменений, первый шаг - передать информацию о файле вашему действию.Самый простой способ сделать это - добавить ссылку в ваше поле file

<input ref={c => this.img = c} ...

Затем в функции onSubmit вы можете использовать эту ссылку для извлечения объекта File из DOM для передачи в полезную нагрузку действия

onSubmit(e) {
  e.preventDefault();

  const playerData = {
    ...this.state,
    file: this.img.files[0]
  }

  this.props.addPlayer(playerData, this.props.history);
}

В действии вам необходимо отправить данные в виде запроса multipart/form-data, для этого вы можете просто передать FormData вaxios и пусть он обрабатывает установку соответствующих заголовков и т. Д.

export const addPlayer = (playerData, history) => dispatch => {
  // build form data
  const form = Object.keys(playerData).reduce((f, k) => {
    f.append(k, playerData[k]);
    return f;
  }, new FormData());
  // send request
  return axios
    .post("api/profile/player", form)
    .then(res => history.push("/dashboard"))
    .catch(err =>
      dispatch({
        type: GET_ERRORS,
        payload: err.response.data
      })
    );
};

Ваш код сервера должен просто работать как есть.

...