Displaying images on react

I need some help displaying my images on my react website. Currently, I am able to input the image into the upload folder and the PostgreSQL database, but I have no way of displaying it. I’ve tried using hooks with fetch to bring my data over, this has not caused any error so it might be my API is wrong or route is wrong. I am not sure and need some help. Please.

Server.Js - Backend folder

app.use(cors({
  origin:true,
  methods:["POST","GET", "PUT", "DELETE"],
  credentials:true
}));
app.use(express.json()); 
app.use('/uploads', express.static(path.resolve(__dirname, './uploads')));

const fileStorageEngine = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "./uploads"); 
  },
  filename: function (req, file, cb) {
    cb(null, new Date().valueOf() + '_' + file.originalname);
},
});

const fileFilter = (req, file, cb) => {
  if(file.mimetype === 'image/jpeg' ||
     file.mimetype === 'image/png' ||
     file.mimetype === 'image/jpg' ||
     file.mimetype === 'image/gif')
     {
    cb(null, true);
  }
  else{
    cb(null, false);
    console.log("Invalid file type.")
  }
}
const upload = multer({
   storage: fileStorageEngine,
   limits:{
     fileSize: 1024 * 1024 * 5
   },
   fileFilter:fileFilter
});

app.post('/api/image', upload.single('image'),  (req, res) => {
  console.log(req.file);
  const { filename, mimetype, size } = req.file;
  const filepath = req.file.path;
  pool.query("INSERT INTO image_files (filename, filepath, mimetype, size) VALUES ($1, $2, $3, $4)", [filename, filepath, mimetype, size])
   .then(() => res.json({ success: true, filename }))
   .catch(err => res.json({ success: false, message: 'upload failed', stack: err.stack })); 
 });
app.get("/api/image/:filename", async (req, res) => {
  const { filename } = req.params;
  pool.query("SELECT * FROM image_files WHERE id = $1", [filename])
     .then(images => {
       if (images[0]) {
     const dirname = path.resolve();
         const fullfilepath = path.join(dirname, images[0].filepath);
         return res.type(images[0].mimetype).sendFile(fullfilepath);
       }
       return Promise.reject(new Error('Image does not exist'));
     })
     .catch(err => res.status(404).json({success: false, message: 'not found', stack: err.stack}),
     );
});

Upload.js - Front end folder

import { toast } from "react-toastify";
import React, { useEffect, useState } from "react";

const Upload = () => {
  const [file, setFile] = useState();
  const [uploadStatus, setUploadStatus] = useState("");
  const [image, setImage] = useState('');
 
  const fileChangeHandler = (e) => {
    setFile(e.target.files[0]);
  };

  const onSubmitHandler = (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append("image", file);
    fetch("http://localhost:5000/api/image", {
      method: "POST",
      body: formData,
      headers: {
        'Accept': "multipart/form-data",
      },
      credentials: "include",
    })
      .then((res) => res.json())
      .then((res) => {
        console.log("File Sent Successful");
        toast.success("File Sent Successfully!");
        setUploadStatus(res.msg);
      })
      .catch((err) => {
        console.log(err.message);
      });
  };

  useEffect(() => {
  fetch("http://localhost:5000/api/image", {
      method: "GET",
      headers: {
        "Content-Type": "application/json, charset=UTF-8",
        'Accept': "application/json, text/html", 
      },
      credentials:'include'
    })
    .then (data => data.json())
    .then ((data) =>{
     console.log(data)
     setImage('http://localhost:5000/' + data.image)
     console.log(image)
    })
  });
  return (
    <div>
      <form id="form" onSubmit={onSubmitHandler} encType="multipart/form-data">
        <input id="myfilefield" type="file" onChange={fileChangeHandler} />
        <hr></hr>
        <button className="btn btn-success" type="submit">
          Upload 
        </button>
        <h2> {uploadStatus} </h2>
        {image && <img src={image} alt="img" />}
      </form>
    </div>
  );
};

export default Upload;

Basically What I’m seeing
image

I am able to display my image on browser if I do something like http://localhost:5000/uploads/

Hi @jasax89, welcome to the forum.

I am quite confused on your server logic: how are you planning the send the file back to the user?

I see you are using

    if(result){
      res.send({
        image: result[0].image,
      });

But what exactly do you expect it to be?
Are you sure you don’t want to send it as a Buffer?
Or maybe you meant sendFile as a response?

Also what’s exactly is your “business” logic?
Why sending the image back to the client?
If you just want to display it, it’s enough to send back the url location where it’s publicly accessible, and then set that as the img src.
So assuming your uploads lives in something like:

/uploads/folder1/asset1.jpg

And that’s accessible you can send the path back to the client for it to use:

<img src="yourdomain.com/[path-to-image]" />

Hope it helps :sparkles:

Sorry, still new at nodejs. So I decided to use:

app.get("/api/image/:filename", async (req, res) => {
  const { filename } = req.params;
  pool.query("SELECT * FROM image_files WHERE id = $1", [filename])
     .then(images => {
       if (images[0]) {
     const dirname = path.resolve();
         const fullfilepath = path.join(dirname, images[0].filepath);
         return res.type(images[0].mimetype).sendFile(fullfilepath);
       }
       return Promise.reject(new Error('Image does not exist'));
     })
     .catch(err => res.status(404).json({success: false, message: 'not found', stack: err.stack}),
     );
});

my uploads live in the backend folder of ‘server>uploads>(images)’
image

<img src="yourdomain.com/[path-to-image]" />

This would get the image directly from the folder, and not as I upload right?

Thanks for letting me know the problem!

With sendFile you don’t need to specify the mime type, it set it based on the filename extension.

Also I see you are sending the file to the client, is it actually intended?

The way you describe it seems to me you want your react frontend to display the image, but there’s no need to send the file back.
You can just use the src filed in the image tag.

So for example if you are able to see your image in the browser by navigating to:
http://localhost:5000/uploads/yourimage

You can display it in an image tag

<img src="http://localhost:5000/uploads/yourimage" />

I am to send the file to the client, so I can do the fetch method in the front-end. I’m suppose to add the images and display the images as I go. I don’t think I can use

<img src="http://localhost:5000/uploads/yourimage" />

Because it is hard coding the file to the image tag.

Sorry for the confusion. Im looking for something like this

image

Then if the user adds more images, it will display next to these. Sort of like a gallery for items, ill be using this for a CRUD menu.

Thanks!

Of course you don’t hard code the string, but in your get method you don’t really want the file per se, you just want a location where those value are stored and accessible.

But it’s your API and you should implement is as you see fit :slight_smile:

Take unsplash as an example: when you make a request to that API they don’t send you the file back, but rather a response with all the metadata and eventually the url you can use to display it:

get photo
So

GET /photos/:id: 

Responds with:

{
  "id": "Dwu85P9SOIk",
  "created_at": "2016-05-03T11:00:28-04:00",
  "updated_at": "2016-07-10T11:00:01-05:00",
  "width": 2448,
  "height": 3264,
[ a lot more stuff... but also]
  "urls": {
    "raw": "https://images.unsplash.com/photo-1417325384643-aac51acc9e5d",
    "full": "https://images.unsplash.com/photo-1417325384643-aac51acc9e5d?q=75&fm=jpg",
    "regular": "https://images.unsplash.com/photo-1417325384643-aac51acc9e5d?q=75&fm=jpg&w=1080&fit=max",
    "small": "https://images.unsplash.com/photo-1417325384643-aac51acc9e5d?q=75&fm=jpg&w=400&fit=max",
    "thumb": "https://images.unsplash.com/photo-1417325384643-aac51acc9e5d?q=75&fm=jpg&w=200&fit=max"
  }
  }
}

So that you can use one of those urls.

I’ve already tried doing this but it doesn’t work and I’m not sure what to do next. There aren’t many resources on fetching data from disk & postgresql online, most of it is for MERN and other stuff. :frowning:

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.