如何将图像从React和Redux传递到后端 [英] How to pass an image to the backend from react and redux

查看:96
本文介绍了如何将图像从React和Redux传递到后端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用MERN堆栈,我希望能够在前端(反应)上载图像,并在后端(express,nodejs)中访问图像以供以后存储.我正在使用multer,但是当我尝试 console.log() req.file 对象时,却一无所获.

I'm using the MERN stack and I want to be able to upload an image in the front end (react) and access it in the backend (express, nodejs) to store it later. I'm using multer but I keep getting undefinied when I try to console.log() the req.file object.

前端:

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

它只是发布播放器数据,然后重定向到另一个组件.

it just post the player data and then redirect to another component.

后端分为两个文件. server.js ,其中设置了所有中间件,并且 profile.js 包含了所有路由.

the backend is divided in two files. server.js where all the middlewares are set up and profile.js that contain all the routes.

后端 server.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. 您使用的内容类型不正确(默认情况下,axios将假定application/json,并且您需要multipart/form-data)
  2. 您似乎以为上载就可以了,因为它是表单的一部分,当您覆盖onSubmit并调用e.preventDefault()时,您将取消该表单的任何默认浏览器行为,并且需要手动将文件发送到服务器(我看不到您当前的代码中发生的任何事情.)
  1. You aren't using the correct content type (axios by default will assume application/json and you need multipart/form-data)
  2. You seem to be assuming the upload will just work because it's part of a form, when you override onSubmit and call e.preventDefault() you cancel any default browser behaviour for that form and need to manually get the file to the server (I don't see any of that happening in your current code).

要使此功能正常运行,几乎不需要进行任何更改,第一步是将文件信息传递给您的操作.最简单的方法是在file字段

Few changes need to happen to get this working, first step is to pass the file information to your action. The simplest way to do this is to add a ref to your file field

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

然后在onSubmit函数中,您可以使用此引用来获取

Then in the onSubmit function, you can use this ref to fetch the File object from the DOM to pass into the action payload

onSubmit(e) {
  e.preventDefault();

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

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

在操作中,您需要将数据作为multipart/form-data请求发送,为此,您只需传递

In the action, you need to send the data as a multipart/form-data request, to do this you can simply pass FormData to axios and let it handle setting the appropriate headers etc.

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

您的服务器代码应该照常工作.

Your server code should just work as is.

这篇关于如何将图像从React和Redux传递到后端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆