I'm learning full-stack by using Js,React and express/post-gres DB I have set up the server on localhost:5003, the server-side app.js is
const express = require("express");
const cors = require("cors");
const app = express();
const data = require("./products.json");
const getTotalProducts = require("./repository");
app.use(cors());
app.get("/api", (req, res) => {
res.status(200).send("Hello from API server");
});
app.get("/products", async (req, res) => {
const totalProducts = await getTotalProducts();
res.send(data.products);
});
module.exports = app;
The products.json has ten products which is
{"products":[
{"id":1,"name":"Angel Wings Harness","description":"The purrrfect accessory to take your kitty to the next level.","price":"$10.00","categoryName":"Accessories","imageName":"cat-photo_0000.jpg","imageDescription":"Wings harness","discountValue":10,"discountType":"percentage off"},
{"id":2,"name":"Deluxe Carry Bag Orange","description":"Backpack-style carry bag with dome.","price":"$20.00","categoryName":"Accessories","imageName":"cat-photo_0001.jpg","imageDescription":"Carry Bag Deluxe","discountValue":null,"discountType":null},
{"id":3,"name":"KittyLove Apron Red","description":"Puff-look apron to protect against dinner time oopsies.","price":"$15.00","categoryName":"Accessories","imageName":"cat-photo_0002.jpg","imageDescription":"Apron","discountValue":null,"discountType":null},
{"id":4,"name":"Outta Space Dome Carry Bag Yellow","description":"Dome-style re-inforced plastic carry bag.","price":"$30.00","categoryName":"Accessories","imageName":"cat-photo_0003.jpg","imageDescription":"Carry Bag Dome","discountValue":null,"discountType":null},
{"id":5,"name":"McMeowful Soft Bow Collar Baby Pink","description":"Hypo-allergenic bow with ultrasoft-style security clip for extra comfort.","price":"$40.00","categoryName":"Accessories","imageName":"cat-photo_0004.jpg","imageDescription":"Stylish Bow Collar","discountValue":null,"discountType":null},
{"id":6,"name":"Jumper Grandad-style Grey","description":"Grandad-style jumper from soft merino wool with button-style clips.","price":"$5.00","categoryName":"Tops","imageName":"cat-photo_0005.jpg","imageDescription":"Jumper Grandad Style","discountValue":null,"discountType":null},
{"id":7,"name":"PartyTime Soldier Outfit Khaki","description":"Party-style soldier outfit, one size fits all.","price":"$100.00","categoryName":"Party outfits","imageName":"cat-photo_0006.jpg","imageDescription":"Soldier Outfit","discountValue":null,"discountType":null},
{"id":8,"name":"PartyTime Sailor Outfit Small","description":"Party-style sailor outfit, size small.","price":"$70.00","categoryName":"Party outfits","imageName":"cat-photo_0007.jpg","imageDescription":"Sailor Outfit","discountValue":null,"discountType":null},
{"id":9,"name":"Angel Wings","description":"The purrrfect accessory to take your kitty to the next level.","price":"$10.00","categoryName":"Accessories","imageName":"cat-photo_0015.jpg","imageDescription":"Wings harness","discountValue":15,"discountType":"fixed amount off"},
{"id":10,"name":"Deluxe Carry Bag Red","description":"Backpack-style carry bag with dome.","price":"$20.00","categoryName":"Accessories","imageName":"cat-photo_0008.jpg","imageDescription":"Carry Bag Deluxe","discountValue":null,"discountType":null}]
}
After I bring up the server I use 'Insomnia" to check the response of my GET request "http:localhost:3002/products" and I can get all the products sent back. Now I'm going to render them in the browser by using React. The client-side App.js looks like
import "./App.css";
import { React, useState, useEffect } from "react";
import Product from "./components/product";
const App = () => {
const [products, setProducts] = useState(null);
useEffect(() => {
const fetchData = async () => {
const response = await fetch("http://localhost:5003/products");
const data = await response.json();
setProducts(data.products);
};
fetchData();
}, []);
return (
<div>
{products.map((product) => (
<Product
name={product.name}
img={product.imageName}
description={product.description}
price={product.price}
/>
))}
</div>
);
};
export default App;
From here I got nothing rendered on the page and it did not fire the fetch function I think--as in the browser devoloper tools I did not see the GET request has been fired.Also in the browser console there're quite a few alerts messages showing there like
react-dom.development.js:86 Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot
printWarning @ react-dom.development.js:86
error @ react-dom.development.js:60
render @ react-dom.development.js:29404
./src/index.js @ index.js:7
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:24
(anonymous) @ startup:7
(anonymous) @ startup:7
App.js:16 after fetch the products is null
App.js:16 after fetch the products is null
App.js:18 Uncaught TypeError: Cannot read properties of null (reading 'map')
at App (App.js:18:1)
at renderWithHooks (react-dom.development.js:16141:1)
at mountIndeterminateComponent (react-dom.development.js:20838:1)
at beginWork (react-dom.development.js:22342:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:4157:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:4206:1)
at invokeGuardedCallback (react-dom.development.js:4270:1)
at beginWork$1 (react-dom.development.js:27243:1)
at performUnitOfWork (react-dom.development.js:26392:1)
at workLoopSync (react-dom.development.js:26303:1)
App @ App.js:18
renderWithHooks @ react-dom.development.js:16141
mountIndeterminateComponent @ react-dom.development.js:20838
beginWork @ react-dom.development.js:22342
callCallback @ react-dom.development.js:4157
invokeGuardedCallbackDev @ react-dom.development.js:4206
invokeGuardedCallback @ react-dom.development.js:4270
beginWork$1 @ react-dom.development.js:27243
performUnitOfWork @ react-dom.development.js:26392
workLoopSync @ react-dom.development.js:26303
renderRootSync @ react-dom.development.js:26271
performSyncWorkOnRoot @ react-dom.development.js:25924
flushSyncCallbacks @ react-dom.development.js:11982
flushSync @ react-dom.development.js:26040
legacyCreateRootFromDOMContainer @ react-dom.development.js:29309
legacyRenderSubtreeIntoContainer @ react-dom.development.js:29335
render @ react-dom.development.js:29419
./src/index.js @ index.js:7
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:24
(anonymous) @ startup:7
(anonymous) @ startup:7
react-dom.development.js:18525 The above error occurred in the <App> component:
at App (http://localhost:3001/static/js/bundle.js:34:82)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
logCapturedError @ react-dom.development.js:18525
update.callback @ react-dom.development.js:18558
callCallback @ react-dom.development.js:13092
commitUpdateQueue @ react-dom.development.js:13113
commitLayoutEffectOnFiber @ react-dom.development.js:23204
commitLayoutMountEffects_complete @ react-dom.development.js:24461
commitLayoutEffects_begin @ react-dom.development.js:24447
commitLayoutEffects @ react-dom.development.js:24385
commitRootImpl @ react-dom.development.js:26651
commitRoot @ react-dom.development.js:26517
performSyncWorkOnRoot @ react-dom.development.js:25956
flushSyncCallbacks @ react-dom.development.js:11982
flushSync @ react-dom.development.js:26040
legacyCreateRootFromDOMContainer @ react-dom.development.js:29309
legacyRenderSubtreeIntoContainer @ react-dom.development.js:29335
render @ react-dom.development.js:29419
./src/index.js @ index.js:7
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:24
(anonymous) @ startup:7
(anonymous) @ startup:7
App.js:18 Uncaught TypeError: Cannot read properties of null (reading 'map')
at App (App.js:18:1)
at renderWithHooks (react-dom.development.js:16141:1)
at mountIndeterminateComponent (react-dom.development.js:20838:1)
at beginWork (react-dom.development.js:22342:1)
at beginWork$1 (react-dom.development.js:27219:1)
at performUnitOfWork (react-dom.development.js:26392:1)
at workLoopSync (react-dom.development.js:26303:1)
at renderRootSync (react-dom.development.js:26271:1)
at performSyncWorkOnRoot (react-dom.development.js:25924:1)
at flushSyncCallbacks (react-dom.development.js:11982:1)
App @ App.js:18
renderWithHooks @ react-dom.development.js:16141
mountIndeterminateComponent @ react-dom.development.js:20838
beginWork @ react-dom.development.js:22342
beginWork$1 @ react-dom.development.js:27219
performUnitOfWork @ react-dom.development.js:26392
workLoopSync @ react-dom.development.js:26303
renderRootSync @ react-dom.development.js:26271
performSyncWorkOnRoot @ react-dom.development.js:25924
flushSyncCallbacks @ react-dom.development.js:11982
flushSync @ react-dom.development.js:26040
legacyCreateRootFromDOMContainer @ react-dom.development.js:29309
legacyRenderSubtreeIntoContainer @ react-dom.development.js:29335
render @ react-dom.development.js:29419
./src/index.js @ index.js:7
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:24
(anonymous) @ startup:7
(anonymous) @ startup:7
BTW the Product component looks like:
const Product = ({ name, img, description, price }) => {
return (
<div className="product">
<h2>{name}</h2>
<img src={`/img/${img}`} alt={description} />
<p>{description}</p>
<p>{price}</p>
</div>
);
};
export default Product;
So what is going on here? why nothing rendered in the browser?
CodePudding user response:
You set the initial value of products
to null
.
const [products, setProducts] = useState(null);
Then you try to call map on it:
{products.map((product) => (
At this time, it isn't an array, and it doesn't have a map
method.
So the app crashes (before the effect hook, that would call fetch
, is run when the render ends).
You need to either:
- Handle the case where it is
null
(e.g. by testing it and returning a loading indicator) - Initialise it to an empty array instead of
null
.
Also in the browser console there're quite a few alerts messages
They are unrelated to your problem … but also very clearly explained in the error messages themselves and the documentation they link to.