React file upload: proper and easy way, with NodeJS

React file upload: proper and easy way, with NodeJS

React file upload: proper and easy way, with NodeJS

Aren't you tired of reloading the page every time you upload anything to the site? This is the ultimate answer to react file upload and issues!

Upload page reloads on submitting a file for upload. Are you a newbie to React, and using this generic style to upload files on the web?

There’s a better way to handle uploads in React.

This tutorial is the answer!

Today, it’ll change forever if you go through this tutorial and implement it on your site.

We’ll use Node with React to upload multiple files at once. As we go along, there will be simple client-side validation and finally with uploaded notification can be shown with react-toastify.

Like always, start a react app with create-react-app

Include the bootstrap CDN in index.html.

In contrast to creating the form from scratch, grab this snippet from bootsnipp.

This is our beautiful upload form to work with.

Single React file upload

Let’s start with a simple one, a single file upload.

Capture selected file

Add a change handler in toapp.js pick the file on change.

 

Log event.target.files, it is an array of all stored files. target.files[0]holds the actual file and its details.

onChangeHandler=event=>{

    console.log(event.target.files[0])

}

On saving, create-react-app will instantly refresh the browser.

Store the file in state, and only upload when a user clicks the upload button.

Initially, the selectedFilestate is set to null

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

  }

To pass the file to the state, setselectedFile state to event.target.files[0].

 onChangeHandler=event=>{
    this.setState({
      selectedFile: event.target.files[0],
      loaded: 0,
    })
  }

Check the state variable again with react-devtools to verify.

Again, create-react-app will instantly refresh the browser and you’ll see the result

Send the files to the server

We have a state of files to upload.

We definitely need an upload button, upload is handled with onClick event handler.

 Upload 

onClickhandle will execute onClickHandler which sends a request to the server. The file from a state is appended as a file to FormData.

onClickHandler = () => {
    const data = new FormData() 
    data.append('file', this.state.selectedFile)
}

We’ll use axios to send AJAX requests.

Install and import axios.

import axios from 'axios';

Create form object and create POST request with axios. It needs endpoint URL and form data.

   axios.post("http://localhost:8000/upload", data, { // receive two parameter endpoint url ,form data 
      })
      .then(res => { // then print response status
        console.log(res.statusText)
      })

Here’s final,onClickhandler with axios POST request. It sends POST request to [http://localhost:8000/upload](http://localhost:8000/upload](http://localhost:8000/upload) "http://localhost:8000/upload](http://localhost:8000/upload)") and gets response.

onClickHandler = () => {
   const data = new FormData()
   data.append('file', this.state.selectedFile)
   axios.post("http://localhost:8000/upload", data, { 
      // receive two    parameter endpoint url ,form data
  })
.then(res => { // then print response status
    console.log(res.statusText)
 })
}

The file type attached is set as a state and needs to be checked. As a result, it’s a binary file.

Axios will send a request to the endpoint with a binary file in Form Data.

To receive the uploaded file, implement a backend server. It’ll receive the file sent from front-end.

Create a simple server with Node.

Create server.js file in the root directory

Install express, multer, and cors.

npm i express multer cors nodemon –save

We’ll use express to create a server, multer to handle files. Cors will be used to enable cross-origin request to this server. Nodemon to monitor the changes and auto-reload, it is optional and you’ll have to restart the server manually in it’s absence.

In,server.js initiate an express instance

var express = require('express');
var app = express();
var multer = require('multer')
var cors = require('cors');

Don’t forget CORS middleware.

app.use(cors())

Create a multer instance and set the destination folder. The code below uses /public folder. You can also assign a new file name upon upload. The code below uses ‘originalfilename’as the file name.

var storage = multer.diskStorage({
      destination: function (req, file, cb) {
      cb(null, 'public')
    },
    filename: function (req, file, cb) {
      cb(null, Date.now() + '-' +file.originalname )
    }
})

Create an upload instance and receive a single file

var upload = multer({ storage: storage }).single('file')

Setup thePOSTroute to upload a file

app.post('/upload',function(req, res) {

    upload(req, res, function (err) {
           if (err instanceof multer.MulterError) {
               return res.status(500).json(err)
           } else if (err) {
               return res.status(500).json(err)
           }
      return res.status(200).send(req.file)

    })

});

Start an upload object and handle an error, check formultererror before general errors. Status OK (200) with metadata is sent back to the client on successful upload.

Make the server listen on port 8000.

app.listen(8000, function() {

    console.log('App running on port 8000');

});

Run nodemon server.js in a terminal to start this server

Upload a file, you will see the file appear in the public directory.

It’s working, congratulations!

Uploading multiple files in React

It’s time for uploading multiple files at once.

Addmultiplein the input field to accept multiple files in the form.



Update andonChangeHandler remove zero indexes, it’s just event.target.files.

onChangeHandler=event=>{
    this.setState({
     selectedFile: event.target.files,
    })
}

Also, update functiononClickHandler to loop through the attached files.

onClickHandler = () => {
   const data = new FormData()
   for(var x = 0; x<this.state.selectedFile.length; x++) {
       data.append('file', this.state.selectedFile[x])
   }

  axios.post("http://localhost:8000/upload", data, { 
      // receive two    parameter endpoint url ,form data
  })

.then(res => { // then print response status
    console.log(res.statusText)
 })

}

In server.js update multer upload instance to accept an array of files.

var upload = multer({ storage: storage }).array('file')

Reload the server and upload multiple files this time.

Is it working for you as well? Let us know if it isn’t.

Handling Validation

Until now, nothing has gone wrong but it doesn’t mean it never will.

Here are situations where this application can crash:

  1. Too many images to upload
  2. Uploading an image with the wrong file extension
  3. Sending an image file that is too large

Client-side validation doesn’t secure the application but can throw errors early to the user and improves the user experience.

#1 There are too many files!

Create a separate function named maxSelectedFile and pass event object.

Use length to check a number of files attached. The code below returns false when a number of files reach 3.

maxSelectFile=(event)=>{
   let files = event.target.files // create file object
       if (files.length > 3) { 
          const msg = 'Only 3 images can be uploaded at a time'
          event.target.value = null // discard selected file
          console.log(msg)
         return false;

     }
   return true;

}

Update onChangeHandler to only set state when the maxSelectFile returns, that is when a number of files are less than 3.

onChangeHandler=event=>{
      var files = event.target.files
      if(this.maxSelectFile(event)){ 
      // if return true allow to setState
         this.setState({
         selectedFile: files
      })
   }
}

The result

#2 Uploading an image with the wrong file extension

Create a checkMimeType function and pass an event object

checkMimeType=(event)=>{
  //getting file object
  let files = event.target.files 
  //define message container
  let err = ''
  // list allow mime type
 const types = ['image/png', 'image/jpeg', 'image/gif']
  // loop access array
  for(var x = 0; x<files.length; x++) {
   // compare file type find doesn't matach
       if (types.every(type => files[x].type !== type)) {
       // create error message and assign to container   
       err += files[x].type+' is not a supported format\n';
     }
   };

 if (err !== '') { // if message not same old that mean has error 
      event.target.value = null // discard selected file
      console.log(err)
       return false; 
  }
 return true;

}

Update onChangeHandler again to include checkMimeType.

onChangeHandler=event=>{
      var files = event.target.files
      if(this.maxSelectFile(event) && this.checkMimeType(event))){ 
      // if return true allow to setState
         this.setState({
         selectedFile: files
      })
   }
}

See the output again.

#3 Uploading an image that is too large

Create another function checkFileSize to check the file size. Define your limiting size and return false if the uploaded file size is greater.

checkFileSize=(event)=>{
     let files = event.target.files
     let size = 15000 
     let err = ""; 
     for(var x = 0; x<files.length; x++) {
     if (files[x].size > size) {
      err += files[x].type+'is too large, please pick a smaller file\n';
    }
  };
  if (err !== '') {
     event.target.value = null
     console.log(err)
     return false
}

return true;

}

Update onChangeHandler again to handle checkFileSize.

onChangeHandler=event=>{
      var files = event.target.files
      if(this.maxSelectFile(event) && this.checkMimeType(event) &&    this.checkMimeType(event)){ 
      // if return true allow to setState
         this.setState({
         selectedFile: files
      })
   }
}

The output thereafter…

That’s all on client-side validation.

Improve UX with progress bar and Toastify

Letting the user know the happening is a lot better than having them stare at the screen until the upload is finished.

To improve the user experience, we can insert progress bar and a popup message

Progress Bar

Use state variable loaded to update real-time values.

Update the state, add loaded: 0

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

The loaded state is changed from progressEvent of the POST request.

axios.post("http://localhost:8000/upload", data, {
       onUploadProgress: ProgressEvent => {
         this.setState({
           loaded: (ProgressEvent.loaded / ProgressEvent.total*100),
       })
   },
})

For progress bar, we use reactstrap.

Install and import progress bar from reactstrap

import {Progress} from 'reactstrap';

Add a progress bar after the file picker.



{Math.round(this.state.loaded,2) }%



See the result in action.

Beautiful, ain’t it?

Display the result message with toastify

Install react-toastify and import the following:

import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

Put the container somewhere


   


Use toast wherever you want to display a message.

First of all, place upload result

.then(res => { 
    toast.success('upload success')
})
.catch(err => { 
    toast.error('upload fail')
})

See the result.

Also, place validation result.

Update checkMimeType function for validation.

checkMimeType=(event)=>{

    let files = event.target.files
    let err = [] // create empty array
    const types = ['image/png', 'image/jpeg', 'image/gif']
    for(var x = 0; x<files.length; x++) {
        if (types.every(type => files[x].type !== type)) {
        err[x] = files[x].type+' is not a supported format\n';
       // assign message to array
      }
    };
    for(var z = 0; z<err.length; z++) { // loop create toast massage
        event.target.value = null 
        toast.error(err[z])
    }
   return true;
}

You’ve the result

Also, add toast.warn(msg)

Include the checkFileSizeand changes from checkMimeType function

checkFileSize=(event)=>{
  let files = event.target.files
  let size = 2000000 
  let err = []; 
  for(var x = 0; x<files.length; x++) {
  if (files[x].size > size) {
   err[x] = files[x].type+'is too large, please pick a smaller file\n';
 }
};
for(var z = 0; z<err.length; z++) {
 toast.error(err[z])
 event.target.value = null
}
return true;
}

Change err variable to array and loop to create toast message from it.

Our react file upload is working fine, but we can have a lot of improvements like uploading to cloud providers , also use of third-party plugins for other services to improve upload experience are some possible additions.

Before we end of this tutorial, you can contribute to improve and refactor code from this tutorial send your PR to this repository.

Top 7 Most Popular Node.js Frameworks You Should Know

Top 7 Most Popular Node.js Frameworks You Should Know

Node.js is an open-source, cross-platform, runtime environment that allows developers to run JavaScript outside of a browser. In this post, you'll see top 7 of the most popular Node frameworks at this point in time (ranked from high to low by GitHub stars).

Node.js is an open-source, cross-platform, runtime environment that allows developers to run JavaScript outside of a browser.

One of the main advantages of Node is that it enables developers to use JavaScript on both the front-end and the back-end of an application. This not only makes the source code of any app cleaner and more consistent, but it significantly speeds up app development too, as developers only need to use one language.

Node is fast, scalable, and easy to get started with. Its default package manager is npm, which means it also sports the largest ecosystem of open-source libraries. Node is used by companies such as NASA, Uber, Netflix, and Walmart.

But Node doesn't come alone. It comes with a plethora of frameworks. A Node framework can be pictured as the external scaffolding that you can build your app in. These frameworks are built on top of Node and extend the technology's functionality, mostly by making apps easier to prototype and develop, while also making them faster and more scalable.

Below are 7of the most popular Node frameworks at this point in time (ranked from high to low by GitHub stars).

Express

With over 43,000 GitHub stars, Express is the most popular Node framework. It brands itself as a fast, unopinionated, and minimalist framework. Express acts as middleware: it helps set up and configure routes to send and receive requests between the front-end and the database of an app.

Express provides lightweight, powerful tools for HTTP servers. It's a great framework for single-page apps, websites, hybrids, or public HTTP APIs. It supports over fourteen different template engines, so developers aren't forced into any specific ORM.

Meteor

Meteor is a full-stack JavaScript platform. It allows developers to build real-time web apps, i.e. apps where code changes are pushed to all browsers and devices in real-time. Additionally, servers send data over the wire, instead of HTML. The client renders the data.

The project has over 41,000 GitHub stars and is built to power large projects. Meteor is used by companies such as Mazda, Honeywell, Qualcomm, and IKEA. It has excellent documentation and a strong community behind it.

Koa

Koa is built by the same team that built Express. It uses ES6 methods that allow developers to work without callbacks. Developers also have more control over error-handling. Koa has no middleware within its core, which means that developers have more control over configuration, but which means that traditional Node middleware (e.g. req, res, next) won't work with Koa.

Koa already has over 26,000 GitHub stars. The Express developers built Koa because they wanted a lighter framework that was more expressive and more robust than Express. You can find out more about the differences between Koa and Express here.

Sails

Sails is a real-time, MVC framework for Node that's built on Express. It supports auto-generated REST APIs and comes with an easy WebSocket integration.

The project has over 20,000 stars on GitHub and is compatible with almost all databases (MySQL, MongoDB, PostgreSQL, Redis). It's also compatible with most front-end technologies (Angular, iOS, Android, React, and even Windows Phone).

Nest

Nest has over 15,000 GitHub stars. It uses progressive JavaScript and is built with TypeScript, which means it comes with strong typing. It combines elements of object-oriented programming, functional programming, and functional reactive programming.

Nest is packaged in such a way it serves as a complete development kit for writing enterprise-level apps. The framework uses Express, but is compatible with a wide range of other libraries.

LoopBack

LoopBack is a framework that allows developers to quickly create REST APIs. It has an easy-to-use CLI wizard and allows developers to create models either on their schema or dynamically. It also has a built-in API explorer.

LoopBack has over 12,000 GitHub stars and is used by companies such as GoDaddy, Symantec, and the Bank of America. It's compatible with many REST services and a wide variety of databases (MongoDB, Oracle, MySQL, PostgreSQL).

Hapi

Similar to Express, hapi serves data by intermediating between server-side and client-side. As such, it's can serve as a substitute for Express. Hapi allows developers to focus on writing reusable app logic in a modular and prescriptive fashion.

The project has over 11,000 GitHub stars. It has built-in support for input validation, caching, authentication, and more. Hapi was originally developed to handle all of Walmart's mobile traffic during Black Friday.

Difference between Node.js and React.js and Angular.js

AngularJS turned the whole definition of web development through its existence, what was lacking in previous methods of development was inappropriate structure. It merges use of JavaScript with MVC and HTML with DOM. ReactJS is a JavaScript library and has a view, but lacks model &amp; controller components. React introduced the concept of virtual DOM which is regarded as one of the greatest advantages of React in comparison of AngularJS. Node.js is a JavaScript-based platform used for developing real-time network applications like a chat software.

AngularJS turned the whole definition of web development through its existence, what was lacking in previous methods of development was inappropriate structure. It merges use of JavaScript with MVC and HTML with DOM. ReactJS is a JavaScript library and has a view, but lacks model & controller components. React introduced the concept of virtual DOM which is regarded as one of the greatest advantages of React in comparison of AngularJS. Node.js is a JavaScript-based platform used for developing real-time network applications like a chat software.