How to send a file/image from React to node.js server

11,185

Finally, I found out how to solve that problem.

 onSubmit = e => {
    e.preventDefault();

    const { user } = this.props.auth;

    const form = new FormData();
    form.append("file", this.state.file);
    form.append("theme", this.state.theme);
    form.append("text", this.state.text);
    form.append("name", user.username);
    form.append("avatar", user.avatar);

    this.props.createPost(form);
  }

Share:
11,185
Ilya Solodeev
Author by

Ilya Solodeev

Updated on June 06, 2022

Comments

  • Ilya Solodeev
    Ilya Solodeev almost 2 years

    I'm trying to send a file/image from React to node.js server with multer. The problem is I can send an image only through Postman but when I'm trying the same in React I'm getting: TypeError: Cannot read property 'path' of undefined. I don't understand whether I should send a file/image in binary or use another format. I've already tried to use reader.readAsDataURL() and reader.readAsBinaryString() but it didn't work.

    
    const multer = require("multer");
    
    const storage = multer.diskStorage({
      destination: (req, file, cb) => {
        cb(null, "./uploads/");
      },
      filename: (req, file, cb) => {
        cb(null, new Date().toISOString() + file.originalname);
      }
    });
    
    const fileFilter = (req, file, cb) => {
      if (
        file.mimetype === "image/jpeg" ||
        file.mimetype === "image/png" ||
        file.mimetype === "image/jpg"
      ) {
        cb(null, true);
      }
      cb(null, false);
    };
    
    const upload = multer({
      storage: storage,
      limits: { fileSize: 5000000 },
      fileFilter: fileFilter
    });
    
    // Create a post
    router.post(
      "/",
      upload.single("image"),
      passport.authenticate("jwt", { session: false }),
    
      (req, res) => {
        const { errors, isValid } = validationPostInput(req.body);
        if (!isValid) {
          return res.status(400).json(errors);
        }
        console.log(req.file);
        const newPost = new Post({
          text: req.body.text,
          theme: req.body.theme,
          name: req.body.name,
          avatar: req.body.avatar,
          image: req.file.path,
          user: req.user.id
        });
    
        newPost.save().then(post => res.json(post));
      }
    );
    
    
      // CREATE A POST
    export const createPost = (userInput, history) => dispatch => {
      const headers = {
        "Content-Type": "form-data"
      };
      axios
        .post("/post", userInput, headers)
        .then(res => history.push("/post/all"))
        .catch(err =>
          dispatch({
            type: GET_ERRORS,
            payload: err.response.data
          })
        );
    };
    
    
    
       import React, { Component } from "react";
    import PropTypes from "prop-types";
    // import { Link } from "react-router-dom";
    import { connect } from "react-redux";
    import { createPost } from "../../actions/postActions";
    import "./style.css";
    
    class CreatePost extends Component {
      state = {
        text: "",
        theme: "",
        image: "",
        errors: {}
      };
    
      componentWillReceiveProps(nextProps) {
        if (nextProps.errors) {
          this.setState({ errors: nextProps.errors });
        }
      }
    
      onSubmit = e => {
        e.preventDefault();
    
        const { user } = this.props.auth;
    
        const newPost = {
          text: this.state.text,
          theme: this.state.theme,
          image: this.state.image,
          name: user.username,
          avatar: user.avatar
        };
    
        this.props.createPost(newPost);
      };
      onChange = e => this.setState({ [e.target.name]: e.target.value });
    
      fileSelectHandler = e => {
        const param = e.target.files[0];
        let reader = new FileReader();
        reader.readAsDataURL(param);
    
        this.setState({
          image: reader.result
        });
        console.log(reader);
      };
    
      render() {
        const { text, theme, errors } = this.state;
    
        return (
          <section className="post">
            <form
              onSubmit={this.onSubmit}
              className="post__form"
              action="/post"
              method="POST"
              encType="multipart/form-data"
            >
              <div className="post__form--input">
                <label>Theme</label>
                <input
                  type="text"
                  name="theme"
                  value={theme}
                  onChange={this.onChange}
                />
                {errors && <small>{errors.theme}</small>}
              </div>
              <div className="post__form--input">
                <label>Text</label>
                <textarea
                  type="text"
                  name="text"
                  value={text}
                  onChange={this.onChange}
                />
                {errors && <small>{errors.text}</small>}
              </div>
              <div className="post__form--file">
                <label>Add Image</label>
                <input
                  type="file"
                  name="file"
                  accept=".png, .jpg"
                  onChange={this.fileSelectHandler}
                />
              </div>
              <button type="submit" className="button">
                Submit
              </button>
            </form>
          </section>
        );
      }
    }
    
    CreatePost.propTypes = {
      errors: PropTypes.object.isRequired
    };
    
    const mapStateToProps = state => ({
      errors: state.errors,
      auth: state.auth
    });
    
    export default connect(
      mapStateToProps,
      { createPost }
    )(CreatePost);
    
    
    • Admin
      Admin almost 5 years
      hey can you generate a prototype here, it will be easy for debugging codesandbox.io/s/node
    • Ilya Solodeev
      Ilya Solodeev almost 5 years
      my server connects to mongoDB, I don't think I can do it
    • Admin
      Admin almost 5 years
      maybe you can mock your data
  • Ilya Solodeev
    Ilya Solodeev almost 5 years
    I changed but I got the same issue. Perhaps the problem in data I'm trying to send. Which format multer can red?