I am currently building a drawing app using React, Node and MongoDB.
It saves images along with name and username in the database. When home page is opened, it has to retrieve and display the image on the screen.
The image is stored in database in the form of a buffer and while displaying it on screen, I am converting it to base64 (found it in some article).
When I try to display it in imagesPage.ejs present inside the node_app for testing purpose, it is properly displaying the image but when I try to do it inside the react component, it is giving the following error:
GET data:image/{image.img.contentType};base64,$(data.img.data.toString('base64')) net::ERR_INVALID_URL
and when I change the image url by removing that extra "image/" before {image.img.contentType}, i get this error :
Failed to load resource: net::ERR_INVALID_URL
react_app part :
I am fetching data in CardData.js and it is fetching it correctly as I verified using console.log :
import React, { useState } from "react";
import Axios from "axios";
export default function CardData(){
const [data, setData] = useState({
lst: []
});
const url = `http://localhost:5000/getDrawings/${localStorage.getItem("user")}`;
Axios.get(url).then((res)=>{
setData(res.data);
}).catch(err=>console.log(err));
return data;
}
Card.js to display the image ( used try…catch to display remaining page even if there’s an error with the image) :
import React, { useEffect, useState } from "react";
import CardData from "./CardData";
function Card(){
const cards = CardData();
try{const allCards = cards.map( function (data) {
//let username = data.username;
console.log("here!!!");
let name = data.name;
let image = `data:{image.img.contentType};base64,$(data.img.data.toString('base64'))`;
return(
<div className = "col-3">
<div className = "adjust">
<div className="image">
<img width="300" height="300" src={image}></img>
</div>
<div className="name">{name}</div>
</div>
</div>
);
})
return [allCards];}
catch(e){ return null;}
}
export default Card;
node_app part :
imageModel.js contains the mongoose schema:
const Mongoose = require('mongoose')
const imageSchema = Mongoose.Schema({
name: {
type: String,
default: ""
},
username: {
type: String,
default: ""
},
img:
{
data: Buffer,
contentType: {
type: String,
default: 'image/png'
}
}
});
module.exports = Mongoose.model('Image',imageSchema);
router.js contains the routes :
const express = require('express')
const router = express.Router()
//const imgModel = require('../models/imageModel')
const {
// other components.
getDrawings,
} = require('../controllers/controllers')
const imgModel = require('../models/imageModel');
//other router.post and router.get
router.get('/getDrawings/:username',getDrawings);
module.exports = router;
controllers.js contains the getDrawings function:
//all necessary imports
const getDrawings = async (req, res) => {
const username = req.params.username;
const items = await imgModel.find({username : username});
//to display imagesPage.ejs I uncomment this and comment out res.send(items)
//res.render('imagesPage',{items : items});
res.send(items);
}
//also exports other functions but removed it from here.
module.exports = {getDrawings};
imagesPage.ejs which correctly displays the image ( it is also used to add images to database, but that is not my current problem ) :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Uploading</title>
</head>
<body>
<h1>Uploaded Images</h1>
<div>
<% items.forEach(function(image) { %>
<div>
<div>
<img src="data:image/<%=image.img.contentType%>;base64,
<%=image.img.data.toString('base64')%>" style="width:300px;height: 300px">
<div>
<h5><%= image.name %></h5>
</div>
</div>
</div>
<% }) %>
</div>
</body>
</html>
the react page correctly displays the name of the image and remaining page but doesn’t display the image and gives the error mentioned above, whereas imagesPage.ejs correctly displays everything.
Please help me out.
Thank you 🙂
3
Answers
When passing in variables in the following assignment:
You have to use
${ }
instead of$( )
Assuming
image.img.contentType
is also a variable in that scopeso, as the server is sending a JSON image, you need to convert JSON to Buffer with Int8Array
then that needs to be converted to Blob, and then create a URL object:
EDIT: use
useEffect
when fetching, that’s what’s giving that loop errortry it now:
Somehow this method did not work for me. Working with the "buffers" did work though.
Here is my setup:
import { Buffer } from 'buffer';
Then just use Buffer.
I tried working with blob for a bit but all the browser displayed was a broken link instead of the image. Not sure why but didn’t dig much after I found this solution.
-> EDIT: Broken link was because of my own stupidity – incorrect field name..uff.
Just to add, I replaced this to use Amazon S3 bucket for images and files as fetching images from DB was taking up considerable time. Since mine is a customer facing B2C website, any second of time taken to load the front page was unacceptable, hence this.