I am trying to get my front-end to call to the back-end for all the "blog posts" that are stored in my MongoDB database. At the moment there is only one document for testing.
On the backend I have this api endpoint:
app.get("/api/blogs", async (req, res) => {
console.log("Getting blog items...");
try{
const blogs = await blogActions.getBlogItems();
res.status(200).json({blogs});
} catch (err) {
console.log(err)
}
});
This calls to a separate JS file with this function:
const { MongoClient } = require('mongodb');
const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);
const connection = async () => {
try {
const database = client.db('personalwebsite');
const blogs = database.collection('blogs');
return blogs;
} catch (err) {
console.log(err);
}
}
const getBlogItems = async () => {
const conn = await connection();
try {
return await conn.find({}).toArray();
} catch (err) {
console.log(err);
}
};
Then in my React front-end I am trying to take the returned array and set it to an Array there in order to map over it and create a new BlogItem component for each blog returned from the database:
import { useState, useEffect } from "react";
import Navbar from "../components/Navbar.tsx";
import BlogItem from "../components/BlogItem.tsx";
import '../styles/Blog.css';
export default function Blog () {
const [isLoggedIn, setIsLoggedIn] = useState<boolean>(false);
const [isAdmin, setIsAdmin] = useState<boolean>(false);
const [token, setToken] = useState<string>('');
const [blogs, setBlogs] = useState([]);
useEffect(() => {
setToken(localStorage.getItem('token'));
async function checkToken () {
const response = await fetch('/api/token', {
method: 'POST',
headers: {
'Content-type': 'application/json',
'Authorization': `Bearer ${token}`
}
});
if (response.ok){
const jsonResponse = await response.json();
if (jsonResponse.delete){
localStorage.clear();
return false;
}
return true;
} else {
console.log("Failed to fetch status of the User Login Session.");
}
}
async function checkIfAdmin () {
const response = await fetch('/api/users/permissions', {
method: 'POST',
headers: {
'Content-type': 'application/json',
'Authorization': `Bearer ${token}`
}
});
if(response.ok) {
const jsonResponse = await response.json();
if (jsonResponse.role === 'admin') {
setIsAdmin(true);
} else {
setIsAdmin(false);
}
}
}
async function getBlogItems () {
try {
const response = await fetch('/api/blogs');
const data = await response.json();
console.log("Before setBlogs", data.blogs)
if(data.blogs.length > 0) {
setBlogs(data.blogs);
}
} catch (err) {
console.log(err);
}
}
if (token) {
checkToken().then(isValid => {
if (!isValid) return;
checkIfAdmin();
});
}
getBlogItems();
}, [])
console.log("After setBlogs", blogs);
return (
<div className="App">
<Navbar />
<main className="main-content">
<div className="blogs-container">
{blogs.length > 0 ? (
blogs.map((blog) => (
<BlogItem
key={blog._id}
title={blog.title}
shortDesc={blog.shortDesc}
imgSrc={blog.imgSrc}
pubDate={blog.pubDate}
/>
))
) : (
<div>Loading...</div>
)}
</div>
<div className="most-popular"></div>
</main>
</div>
);
}
I have tried quite a few different methods for trying to get this to work correctly. At first I thought it was just a problem with the data not being returned quickly enough but even after getting the code to wait for the data to be returned and getting the Array to set. I get an error that Objects are not valid as a React child.
This is meant to be an array of Objects so that I can access the properties of each object for the elements in the component but I cannot get it to work for the life of me. I spent awhile using ChatGPT to try and get some progress out of it but this seems to be a problem that requires human intervention instead.
CodePudding user response:
So this is annoying but the issue wasn't with the rest of my code but actually that the BlogItem component had the props wrapped only in parentheses.
Here is the component:
export default function BlogItem ({title, shortDesc, imgSrc, pubDate}) {
return (
<div className="blog-item">
<img src={imgSrc} className="blog-image" />
<h1 className="blog-title">{title === "" ? "Placeholder Title" : title }</h1>
<p className="blog-short-desc">{shortDesc}</p>
<p className="blog-date">{pubDate}</p>
</div>
);
}
The fix was that title, shortDesc, imgSrc, pubDate. All needed to be wrapped in Curly Braces. It now works :\