简体   繁体   English

为什么在我的 React 应用程序中无法获取 function

[英]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我正在通过使用 Js、React 和 express/post-gres DB 来学习全栈 我已经在 localhost:5003 上设置了服务器,服务器端 app.js 是

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.json 有十个产品是

{"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启动服务器后,我使用“Insomnia”检查我的 GET 请求“http:localhost:3002/products”的响应,我可以将所有产品发回。现在我将在浏览器中呈现它们使用 React。客户端 App.js 看起来像

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从这里我没有在页面上呈现任何东西,它没有触发提取 function 我认为 - 因为在浏览器开发者工具中我没有看到 GET 请求已被触发。在浏览器控制台中也有很多警报消息显示在那里

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?为什么没有在浏览器中呈现?

You set the initial value of products to null .您将products的初始值设置为null

 const [products, setProducts] = useState(null);

Then you try to call map on it:然后您尝试在其上调用 map:

 {products.map((product) => (

At this time, it isn't an array, and it doesn't have a map method.此时,它不是数组,也没有map方法。

So the app crashes (before the effect hook, that would call fetch , is run when the render ends).因此应用程序崩溃(在渲染结束时运行会调用fetch的效果挂钩之前)。

You need to either:您需要:

  • Handle the case where it is null (eg by testing it and returning a loading indicator)处理它是null的情况(例如通过测试它并返回加载指示器)
  • Initialise it to an empty array instead of null .将其初始化为一个空数组而不是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.它们与您的问题无关……但在错误消息本身和它们链接到的文档中也有非常清楚的解释。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM