'Why the fetch function does not work from my React app
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?
Solution 1:[1]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Quentin |
