I am building a React application where a parent component (Dashboard.js) manages a table of companies and products they have. The products are created in a child component (CreateProduct.js) and passed to the parent through a callback function (onProductCreated). However, the data does not display in the table as expected.
I am using the useState hook to manage an array of products in the parent component. When a new product is created in the child component, the product data is passed to the parent and added to the state. I expect the table to update and display the data, but the table remains empty.
My frontend is written in ReactJS and backend in ExpressJS.
Here are the code samples:
Dashboard.js:
import React, { useState, useEffect } from "react";
import CreateProduct from "./CreateProduct";
import CreateCompany from "./CreateCompany";
import { Button } from "antd";
import axios from "axios";
function Dashboard() {
const [products, setProducts] = useState([]);
// Fetch products from the server
useEffect(() => {
const fetchProducts = async () => {
try {
const response = await axios.get("http://localhost:5000/api/products");
if (response.data.success) {
setProducts(response.data.products); // Assuming API response contains a 'products' array
} else {
console.error("Failed to fetch products:", response.data.message);
}
} catch (error) {
console.error("Error fetching products:", error);
}
};
fetchProducts();
}, []); // Empty dependency array ensures this runs once on mount
const handleProduct = (newProduct) => {
console.log("New Product:", newProduct); // Debug product data
setProducts((oldProduct) => [...oldProduct, newProduct]);
};
return (
<div>
<h1>Create Product and Company</h1>
<CreateProduct onProductCreated={handleProduct} />
<table border="1" style={{ marginTop: "20px" }}>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Category</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{products.map((product, index) => (
<tr key={index}>
<td>{product.id}</td>
<td>{product.name}</td>
<td>{product.category}</td>
<td>{product.amount}</td>
</tr>
))}
</tbody>
</table>
{products.length > 0 && (
<CreateCompany productId={products[products.length - 1].id} /> // Pass the last profile ID
)}
<Button type="primary" style={{ marginTop: "20px" }}>
Add Company
</Button>
<Button type="primary" style={{ marginTop: "30px" }}>
Add Product
</Button>
</div>
);
}
export default Dashboard;
CreateProduct.js:
import React, { useState } from "react";
import axios from "axios";
function CreateProduct({ onProductCreated }) {
const [productName, setProductName] = useState("");
const [productCategory, setProductCategory] = useState("");
const [productAmount, setProductAmount] = useState("");
const [productUnit, setProductUnit] = useState("");
const [productOwner, setProductOwner] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post(
"http://localhost:5000/api/create/product",
{
productName,
productCategory,
productAmount,
productUnit,
productOwner,
}
);
if (response.status === 200) {
alert("Product Created");
onProductCreated({
id: response.data.id,
name: productName,
category: productCategory,
amount: productAmount,
}); // Pass the productId to the parent component
}
} catch (error) {
console.error("Error creating product:", error);
alert("Product creation failed.");
}
return (
<form onSubmit={handleSubmit}>
<div>
<label style={{ fontSize: "20px" }}>Company Website:</label>
<input
type="text"
value={productName}
onChange={(e) => setProductName(e.target.value)}
required
/>
</div>
<div>
<label style={{ fontSize: "20px" }}>Company Website:</label>
<input
type="text"
value={productCategory}
onChange={(e) => setProductCategory(e.target.value)}
required
/>
</div>
<div>
<label style={{ fontSize: "20px" }}>Company Website:</label>
<input
type="text"
value={productAmount}
onChange={(e) => setProductAmount(e.target.value)}
required
/>
</div>
<div>
<label style={{ fontSize: "20px" }}>Company Website:</label>
<input
type="text"
value={productUnit}
onChange={(e) => setProductUnit(e.target.value)}
required
/>
</div>
<button type="submit" style={{ marginTop: "10px" }}>
Create Company
</button>
</form>
);
};
}
export default CreateProduct;
CreateCompany.js:
import React, { useState } from "react";
import axios from "axios";
function CreateCompany({ productId }) {
const [companyName, setCompanyName] = useState("");
const [companyNumber, setCompanyNumber] = useState("");
const [companyCountry, setCompanyCountry] = useState("");
const [companyWebsite, setCompanyWebsite] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post(
"http://localhost:5000/api/create/company",
{
companyName,
companyNumber,
companyCountry,
companyWebsite,
productId,
}
);
if (response.status === 200) {
alert("Company Created");
}
} catch (error) {
console.error("Error creating company:", error);
alert("Company creation failed.");
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label style={{ fontSize: "20px" }}>Company Name:</label>
<input
type="text"
value={companyName}
onChange={(e) => setCompanyName(e.target.value)}
required
/>
</div>
<div>
<label style={{ fontSize: "20px" }}>Company Number:</label>
<input
type="text"
value={companyNumber}
onChange={(e) => setCompanyNumber(e.target.value)}
required
/>
</div>
<div>
<label style={{ fontSize: "20px" }}>Company Country:</label>
<input
type="text"
value={companyCountry}
onChange={(e) => setCompanyCountry(e.target.value)}
required
/>
</div>
<div>
<label style={{ fontSize: "20px" }}>Company Website:</label>
<input
type="text"
value={companyWebsite}
onChange={(e) => setCompanyWebsite(e.target.value)}
required
/>
</div>
<button type="submit" style={{ marginTop: "10px" }} disabled={!productId}>
Create Company
</button>
</form>
);
}
export default CreateCompany;
Company.js:
const mongoose = require("mongoose");
const product = require("./Product");
const CompanySchema = new mongoose.Schema({
name: String,
number: Number,
country: String,
website: String,
products: [{
type: mongoose.Schema.Types.ObjectId,
ref: "product",
}],
});
const company = mongoose.model("company", CompanySchema);
module.exports = company;
Product.js:
const mongoose = require("mongoose");
const ProductSchema = new mongoose.Schema({
name: String,
category: String,
amount: Number,
unit: String,
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: "company",
}
});
const product = mongoose.model("product", ProductSchema);
module.exports = product;
Edit 1
I figured out that i dont have a get endpoint on backend so i added a get endpoint. And i added that endpoint in my router. When i trigger get product endpoint it returns 200 but response is just an empty json object. And my main problem still persists.
getProduct.js:
const express = require("express");
const Product = require("../schema/Product"); // Adjust the path as needed
const router = express.Router();
router.get("/api/products", async (req, res) => {
try {
const products = await Product.find(); // Fetch all products
res.status(200).json({ success: true, products });
} catch (error) {
console.error("Error fetching products:", error);
res.status(500).json({ success: false, message: "Server error" });
}
});
module.exports = router;
route.js
const express = require("express");
const login = require("../auth/login");
const signup = require("../auth/signup");
const getCompany = require("../db/getCompany");
const getProduct = require("../db/getProduct");
const router = express.Router();
router.post("/login", login);
router.post("/signup", signup);
router.post("/create/company", (req, res) => {
res.json({ message: "Company created successfully" });
});
router.post("/create/product", (req, res) => {
res.json({ message: "Product created successfully" });
});
router.get("/products", (req, res) => {
res.json({ product: getProduct });
});
router.get("/company", (req, res) => {
res.json({ company: getCompany });
});
router.get("/logout", (req, res) => {
res.clearCookie("token");
res.json({ message: "Logged out" });
});
module.exports = router;