Search code examples
javascriptnode.jsreactjsexpressmulter

Getting the error as "TypeError: Cannot read property 'file' of undefined" when uploading a video using Multer


The task is to choose a video file from the desktop and upload it to the site. Then this video file will be automatically uploaded to a Youtube channel you have provided using GCD.

I am getting the error as "react-dom.development.js:4091 Uncaught TypeError: Cannot read property 'file' of undefined at handleSubmit (App.js:30)"

Below is the backend code :

const express = require("express")

const youtube = require("youtube-api");

const uuid = require("uuid")

const cors = require("cors");

const open = require("open");

const multer = require("multer")

const fs = require("fs")

const credentials = require("./GCD credentials.json.json")
const app = express();


app.use(express.json());
app.use(cors());

const storage = multer.diskStorage({
    destination: './',
    filename(req, file, cb){
        const newFileName = `${uuid()}-${file.originalname}`
        cb (null, newFileName);
    }
})

const uploadVideo = multer({
    storage : storage
}).single("videoFile")

app.post('/upload' , uploadVideo, (req, res) =>{
    if (req.file) {
         const filename = req.file.filename;
         const {title, description} = req.body;

    open(oAuth.generateAuthUrl({
        access_type : 'offline',
        scope: "https://wwww.googleapis.com/auth/youtube.uplaod",
        state : JSON.stringify({
            filename,
            title,
            description
        })
    }))
}
})

app.get('/oauth2callback', (req,res) =>{
    res.redirect("http://localhost:3001/Success")
const {filename, title, description}  = JSON.parse(req.query.state);

oAuth.getToken(req.query.code, (err, tokens) =>{
    if (err) {
        console.log(err);
        return;
    }

    oAuth.setCredentials(tokens);
    youtube.insert({
        resorces:{
            // Again in documentation
            snippet: {title, description},
            status : {privacyStatus : 'private'}
        },
        part : 'snippet,status',
        media: {
            // fs(file sysytem) is used for uploading
            body : fs.createReadStream(filename)
        }
    },(err, data) =>{
        console.log("Done finally. You acn exit");
        process.exit();
    })
})

})

const oAuth = youtube.authenticate({
    type: "oauth",
    client_id : credentials.web.client_id,
    client_secret : credentials.web.client_secret,
    redirect_url : credentials.web.redirect_uris[0],
})

const port = 3000;

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

Here is the frontend code :

import React, { useState } from "react";

const axios = require('axios').default;

const App = () => {

  const [form, setForm] = useState({
    title: "",
    description: "",
    file: null,
  });

  const handleChange = (event) =>{
    const inputValue = event.target.name === "file" ? event.target.files[0] : event.target.value;
    setForm({
      ...form,
      [event.target.name] : inputValue
    })
  }

  const handleSubmit = (event) =>{
     event.preventDefault();

    const videoData = new FormData ();

    videoData.append("videoFile".form.file);
    videoData.append("title".form.title);
    videoData.append("description".form.description);

    axios.post("http://localhost:3001/upload", videoData)
  .then(response =>{
    console.log(response.data);
  })
  }

  

  return (
    <div>
      <h1>Welcome to Tech Pose Tube !!!</h1>
      <form className="w-25 " onSubmit  = {handleSubmit}>
        <div class="form-group">
          <label for="exampleInputTitle">Title</label>
          <input
            type="text"
            class="form-control"
            placeholder="Enter the title of your video"
            onChange = {handleChange}
            name = "title"
          />
        </div>
        <div class="form-group">
          <label for="exampleInputDescription">Description</label>
          <textarea
           type="text" 
           class="form-control" 
           onChange = {handleChange}
           name = "description"
           />
        </div>
        <div class="form-group">
          <label for="exampleFormControlFile1">Choose your video file</label>
          <input
            type="file"
            accept = "video/mp4"
            onChange = {handleChange}
            name = "file"
          />
          <br />
        <button type="submit" class="btn btn-primary">
          Submit
        </button>
        </div>
      </form>
    </div>
  );
};

export default App;

Solution

  • As the error said:

    "react-dom.development.js:4091 Uncaught TypeError: Cannot read property 'file' of undefined at handleSubmit (App.js:30)"
    

    It's the problem with your frontend code. I saw a typo in this part, you should replace "." by ","

        videoData.append("videoFile".form.file); //---> should be videoData.append("videoFile", form.file);
        videoData.append("title".form.title); // same as above
        videoData.append("description".form.description); // same as above
    

    The document here in case you need it.

    Another issue, you're listening on port 3000 in the backend code, so the frontend code to send request should be :

    axios.post("http://localhost:3000/upload", videoData);