尝试在 React 前端渲染 MongoDB 条目 10 秒后超时

Posted

技术标签:

【中文标题】尝试在 React 前端渲染 MongoDB 条目 10 秒后超时【英文标题】:Attempt to render MongoDB entries in React front-end times out after 10 seconds 【发布时间】:2021-01-26 12:14:33 【问题描述】:

我想渲染一张“卡片”,其中包含从 MongoDB 数据库中提取的某些细节,并作为道具传递给 React 前端。后端是一个无服务器功能。

目前,我无法让我的 React 代码找到我的 MongoDB 条目。它不断超时并显示以下错误消息:

2020-10-12T15:25:11.119Z    cde99f57-0da2-4b71-9fc1-d2eda3c1369c    ERROR   (node:8) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option  useUnifiedTopology: true  to the MongoClient constructor.
2020-10-12T15:25:21.062Z cde99f57-0da2-4b71-9fc1-d2eda3c1369c Task timed out after 10.01 seconds

每次重新加载页面后都会发生这种情况 - 请求一直超时。

谁能指出我在这里做错了什么?

这是我的代码...

架构:

const mongoose = require("mongoose");
const Schema = mongoose.Schema;


const SubmitDebtSchema = new Schema (
  creditCard: String,
  personalLoan: String,
  provider: String,
  balance: Number,
  limit: Number,
  monthly: Number,
  interest: Number,
  borrowed: Number
);

module.exports = mongoose.model('submitdebts', SubmitDebtSchema);

我的“获取”API 函数:

const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const SubmitDebt = require("./submitDebtSchema");

require("dotenv").config();

const app = express();

app.use(bodyParser.urlencoded(
  extended: true
));

mongoose.connect(`mongodb+srv://$process.env.MONGO_USER:$process.env.MONGO_PASSWORD@otter-money.f9twk.mongodb.net/test?retryWrites=true&w=majority`, useNewUrlParser: true, useUnifiedTopology: true);


module.exports = async (req, res) => 

  res.statusCode = 200;
  res.setHeader("Content-Type", "application/json");

  await SubmitDebt.find();
;

我的反应代码:

class IndividualDebts extends Component 
  constructor(props) 
    super(props)

    this.state = 
      debts: 
    

    this.getDebtCards = this.getDebtCards.bind(this);
    this.renderDebtCards = this.renderDebtCards.bind(this);
  

  componentDidMount = () => 
    this.getDebtCards()
  

  getDebtCards = () => 
    axios.get("/api/fetchDebtCards")
      .then((res) => 
      const data = res.data
      this.setState (
        debts: data
      )
      console.log("Data has been received.")
    )
    .catch((error) => 
      alert("Error fetching the data.")
      console.log(error)
    )
  

  renderDebtCards = (debts) => 
    if (!this.state.debts.length) 
      return null
    

    this.state.debts.map((debt, index) => 
      return (
        <div>
        <IndividualDebtCard key=index
          provider=debt.provider
          type=debt.creditCard === 'true' ? debt.creditCard : "Personal Loan" 
          balance=debt.balance
          limit=debt.creditCard === 'true' ? debt.limit : debt.borrowed
          monthly=debt.monthly
          interest=debt.interest />
        </div>
      )
    )
  


  render() 
    return (
      <div>
        <section className="individual-debts-section">
          <div className="individual-debts-container">
            <div className="individual-debts-heading">
              <h3>Individual Breakdown</h3>
            </div>

            <div className="individual-debts-card-container">

              this.renderDebtCards()

            </div>

我觉得它真的很接近,但我就是不知道我做错了什么!有什么建议吗?

谢谢

【问题讨论】:

对象的方法是什么? mongoose 文档只说明 find。 尝试添加“.default”,现在“SubmitDebt”在错误日志中是匿名的。我指的文档也是这样的:mongoosejs.com/docs/api.html#model_Model.find 嘿 - 再次感谢您的回复。真的很感激。我真的不明白我需要如何根据您的最新回复重构我的代码。您能否为我添加一个答案以便我查看? 请查看:***.com/questions/34241970/… 感谢您的反馈。我现在已经转换了我的代码以反映答案。它仍然无法正常工作,但会更新我的问题以反映新的错误消息。 【参考方案1】:

您的 API 设置存在一些问题...

解决方案的问题

调整您的 submitdebts 模型以返回当前注册的模型或使用 mongoose 连接注册架构:

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

...Schema

module.exports = mongoose.models.submitdebts || mongoose.model('submitdebts', SubmitDebtSchema);

如果您的前端和后端在不同的进程上运行,则需要添加 CORS 标头(我喜欢将 package 用于 CORS):

/*
 Either add CLIENT to your .env files:
 
 CLIENT: http://example.com (for production)
 CLIENT: http://localhost:3000 (for development)
 ...etc

 or add it to your your startup script in the package.json:
 
 for example: "dev": "NODE_ENV=development CLIENT=http://localhost:3000 node server.js"

  This is important to allow requests from the client
*/
...required imports
const cors = require("cors");

const  CLIENT, ...etc  = process.env;

...startup script

app.use(
  cors( 
    origin: CLIENT 
  )
);

...listen to port

mongoose.connect 是异步的,因此您当前在连接和启动服务器时会遇到竞速情况。相反,您应该等待连接解决,然后启动您的快速服务器。此外,您检索文档的控制器没有正确响应客户端的请求:


const  CLIENT, MONGO_USER, MONGO_PASSWORD, PORT  = process.env;

const options = 
  useNewUrlParser: true, // avoids DeprecationWarning: current URL string parser is deprecated
  useCreateIndex: true, // avoids DeprecationWarning: collection.ensureIndex is deprecated.
  useFindAndModify: false, // avoids DeprecationWarning: collection.findAndModify is deprecated.
  useUnifiedTopology: true // avoids DeprecationWarning: current Server Discovery and Monitoring engine is deprecated
;

(async () => 
  try 
    // if this fails to connect after 10 seconds, it'll kill the process
    // so make sure your credentials and host URL are correct!!!!!
    await mongoose.connect(`mongodb+srv://$MONGO_USER:$MONGO_PASSWORD@otter-money.f9twk.mongodb.net/test?retryWrites=true&w=majority`, options);

    const app = express();

    app.use(bodyParser.urlencoded( extended: true ));
   
    // this now tells express to accept requests from the client
    app.use(
      cors( 
        origin: CLIENT 
      ) 
    );

    // this will accept any GET requests to "/api/fetchDebtCards" 
    // and respond with "debts" (can be named anything)
    app.get("/api/fetchDebtCards", async (req, res) => 
      try 
        const debts = await SubmitDebt.find();
    
        res.status(200).json( debts );
        /*
          Optionally, you can use:
          
          res.status(200).send(debts) 
 
          which will allow "debts" to be directly accessible from "res.data"
        */ 
       catch (error) 
        res.status(400).json( error );
      
    );

    app.listen(PORT, (err) => 
      if (err) throw err;
      console.log(`Listening for requests from: \x1b[1m$CLIENT\x1b[0m\n`);
    );
   catch (err) 
    console.log(err.toString());
    process.exit(1);
  
)();

现在在客户端上,您应该能够从 res.data.debts 检索“债务”文档(我更喜欢 async/await 而不是 thenables,但取决于您):

   getDebtCards = async () => 
     try 
       const res = await axios.get("/api/fetchDebtCards");

       console.log("Data has been received: ", JSON.stringify(res.data.debts, null, 4))

       this.setState( debts: res.data.debts );
      catch(error) 
       alert("Error fetching the data.")

       console.log(error)
     
  

代码

server.js

require("dotenv").config();
const bodyParser = require("body-parser");
const cors = require("cors");
const express = require("express");
const mongoose = require("mongoose");
const SubmitDebt = require("./submitDebtSchema");

const  CLIENT, MONGO_USER, MONGO_PASSWORD, PORT  = process.env;

const options = 
  useNewUrlParser: true,
  useCreateIndex: true, 
  useFindAndModify: false, 
  useUnifiedTopology: true
;

(async () => 
  try 
    await mongoose.connect(`mongodb+srv://$MONGO_USER:$MONGO_PASSWORD@otter-money.f9twk.mongodb.net/test?retryWrites=true&w=majority`, options);

    const app = express();

    app.use(bodyParser.urlencoded( extended: true ));
   
    app.use(
      cors( 
        origin: CLIENT 
      ) 
    );

    app.get("/api/fetchDebtCards", async (req, res) => 
      try 
        const debts = await SubmitDebt.find();

        res.status(200).json( debts );
       catch (error) 
        res.status(400).json( error );
      
    );

    app.listen(PORT, (err) => 
      if (err) throw err;
      console.log(`Listening for requests from: \x1b[1m$CLIENT\x1b[0m\n`);
    );
   catch (err) 
    console.log(err.toString());
    process.exit(1);
  
)();

结论

您应该能够只启动 express 服务器并使用Postman 对其进行查询。例如,我在http://localhost:5000 运行一个开发快递服务器,我将使用GET http://localhost:5000/api/users 进行查询,我将返回users 的JSON 响应:

【讨论】:

感谢详细的回复。这段代码不可避免地会比我的更彻底和更有效,但最后我发现我的 Axios 查询有问题,而且我没有在我的 Fetch API 文件中返回正确的 JSON。我会接受但没有使用它 - 感谢您的宝贵时间!【参考方案2】:

在 JSX 中调用 this.rennderDebtCards 方法时,您没有提供任何参数。要么传递 this.state.debts,要么直接在你的方法中使用 this.state.debts

renderDebtCards = () => 
    if (this.state.debts.length === 0) 
      return null
    

    return this.state.debts.map((debt, index) => 
      return (
        <div>
        <IndividualDebtCard key=index
          provider=debt.provider
          type=debt.creditCard === 'true' ? debt.creditCard : "Personal Loan" 
          balance=debt.balance
          limit=debt.creditCard === 'true' ? debt.limit : debt.borrowed
          monthly=debt.monthly
          interest=debt.interest />
        </div>
      )
    )
  

【讨论】:

嘿 - 我试过这个,但不幸的是它没有用。我在函数日志中收到一条单独的错误消息,提示“SubmitDebt.find() 不是函数”。 我认为这意味着您正在尝试对不允许执行的事情执行 mongo 查询。检查您的 SubmitDebt 是否正确导入并且是您的 mongo 模型 嘿 - 我已经做到了。我认为没关系,但为了安全起见,我已经添加了所有代码。如果您对更新后的问题有任何反馈,我们将不胜感激!

以上是关于尝试在 React 前端渲染 MongoDB 条目 10 秒后超时的主要内容,如果未能解决你的问题,请参考以下文章

如何在服务器端渲染中使用 Mongodb

使用 node.js + react 服务器端渲染 + 通量 + mongodb 时的数据耦合策略

React 正在渲染 [object object] 而不是 JSX

前端React 条件渲染

5种在React中实现条件渲染的方法

第 005 期 Vue 运行时性能优化之减少渲染组件的次数