Home > database >  Why the fetch function does not work from my React app
Why the fetch function does not work from my React app

Time:04-14

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.

  • Related