React没有显示来自express后端的数据

huangapple go评论62阅读模式
英文:

React is not displaying data from express backend

问题

你的前端代码似乎存在一些问题,导致表格数据不显示。问题可能出现在MonsterList.jsx文件中。以下是有关你前端代码中可能出现问题的部分:

import "./Monsters.css";
import React, { useEffect, useContext } from 'react';
import MonsterFinder from "../apis/MonsterFinder";
import { useNavigate, Link } from "react-router-dom";
import { MonsterContext } from '../context/MonsterContext';

const MonsterList = (props) => {
    const { monsters, setMonsters } = useContext(MonsterContext);
    const navigate = useNavigate()

    useEffect(() => {
        const fetchData = async () => {
        try {
          const response = await MonsterFinder.get("/monsters");
           setMonsters(response.data.data.monsters);
          
        } catch (err) {}
    };
       fetchData();     
    }, []);

    return (
             
        <div className="app-container">
            <h1>Monsters</h1>
            <table>
                <thead>
                    <tr>
                        <th> </th>
                        <th>Cr</th>
                        <th>Name</th>
                        <th>Source</th>
                        <th>Type</th>
                        <th>Size</th>
                        <th>Alignment</th>
                        <th>Tag</th>
                        <th>Info</th>
                    </tr>
                </thead>
                <tbody>
                    {monsters.map((monster) => {
                        return (
                        <tr>
                            <td><img src={require(`../media/${monster.Image}`)} alt={monster.Name} height="25" width="25" /></td>
                            <td>{monster.Cr}</td>
                            <td>{monster.Name}</td>
                            <td>{monster.Source}</td>
                            <td>{monster.Type}</td>
                            <td>{monster.Size}</td>
                            <td>{monster.Alignment}</td>
                            <td><button className="button"><Link className="links" to={`/monsterinfo/${monster.Name}`}>Info</Link></button></td>
                        </tr>
                        );
                    })}
                    
                </tbody>
            </table>
        </div>
        
    )
};

export default MonsterList

首先,确保在 MonsterFinder.get("/monsters") 中正常获取到数据,你可以在 useEffect 中使用 console.log(response.data) 来验证数据是否被正确获取。

如果数据获取没有问题,检查 monsters 数组是否包含数据。如果 monsters 是空数组,那么表格中不会显示数据。确保数据被正确设置到 monsters 中。

最后,确保 monsters.map() 函数被正确执行,以便将数据渲染到表格中。

如果你确认数据获取和设置都正常,但问题仍然存在,可能需要检查CSS样式是否正确,以确保表格元素正确显示。

英文:

I am trying to get data from a postgres database and display that in a table.

server.js

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

require(&quot;dotenv&quot;).config();
const cors = require(&quot;cors&quot;)
const db = require(&quot;./db&quot;);
// Express Application setup
const express = require(&quot;express&quot;);
const morgan = require(&quot;morgan&quot;);
const app = express();
const bodyParser = require(&quot;body-parser&quot;);
const port = process.env.PORT;
app.listen(port, () =&gt; {
console.log(`Server is UP and running and listening on port ${port}`);
})
app.use(cors());
app.use(bodyParser.json());
// HTTP request logger middleware
app.use(morgan(&quot;dev&quot;));
// Get All Monsters
app.get(&#39;/monsters&#39;, async  (req, res) =&gt; {
const results = await db.query(`select * from monsters`, (err, results) =&gt; {
if (!err) {
console.log(results)
res.send(results.rows);
}
});
db.end;
})

<!-- end snippet -->

the server is on port 3100, and when I visit http://localhost:3100/monsters I get a good result:

[{"id":1,"image":{"type":"Buffer","data":[105,109,103,49,46,106,112,103]},"table":null,"cr":"1/2","source":"Monster Manual","type":"Humanoid","size":"Medium","alignment":"N","tags":null,"info":null,"name":"Goblin"},{"id":13,"image":null,"table":null,"cr":"1/4","source":"Monster Manual","type":"Monster","size":"Medium","alignment":"N","tags":null,"info":null,"name":"Spiderz"}]

Also works fine from Postman. The only thing I see in difference that when I run GET in Postman Morgan shows me GET /monsters 200 41.481 ms , and from the website it shows me: GET /monsters 304 3.514 ms.

The problem seems to sit somewhere in the frontend (react).

App.js:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import &#39;./App.css&#39;;
import MainComponent from &#39;./components/MainComponent&#39;;
import Info from &#39;./components/Info&#39;;
import Rules from &#39;./components/Rules&#39;;
import Rulebooks from &#39;./components/Rulebooks&#39;;
import Monsters from &#39;./components/Monsters&#39;;
import Adventures from &#39;./components/Adventures&#39;;
import Contact from &#39;./components/Contact&#39;;
import { Routes, Route } from &#39;react-router-dom&#39;;
import MonsterInfo from &#39;./components/MonsterInfo&#39;;
import { MonsterContextProvider } from &#39;./context/MonsterContext&#39;;
function App() {
return (
&lt;MonsterContextProvider&gt;
&lt;div&gt;
&lt;Routes&gt;
&lt;Route path=&quot;/&quot; element={&lt;MainComponent /&gt;} /&gt;
&lt;Route path=&quot;/info&quot; element={&lt;Info /&gt;} /&gt;
&lt;Route path=&quot;/rules&quot; element={&lt;Rules /&gt;} /&gt;
&lt;Route path=&quot;/rulebooks&quot; element={&lt;Rulebooks /&gt;} /&gt;
&lt;Route path=&quot;/monsters&quot; element={&lt;Monsters /&gt;} /&gt;
{/* &lt;Route path=&quot;/monsters/:id&quot; element={&lt;MonsterInfo /&gt;} /&gt; */}
&lt;Route path=&quot;/adventures&quot; element={&lt;Adventures /&gt;} /&gt;
&lt;Route path=&quot;/contact&quot; element={&lt;Contact /&gt;} /&gt;
&lt;/Routes&gt;
&lt;/div&gt;
&lt;/MonsterContextProvider&gt;
)
};
export default App;

<!-- end snippet -->

context: MonsterContext.js

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import React, { useState, createContext } from &quot;react&quot;;
export const MonsterContext = createContext();
export const MonsterContextProvider = props =&gt; {
const [monsters, setMonsters] = useState([])
// const addMonsters = (monsters) =&gt; {
//     setMonsters([...monsters, monsters]);
// }
return (
&lt;MonsterContext.Provider value={{ monsters: monsters, setMonsters }}&gt;
{props.children}
&lt;/MonsterContext.Provider&gt;
)
}

<!-- end snippet -->

Api: Monsterfinder.js

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

import axios from &quot;axios&quot;;
export default axios.create({
baseURL: &quot;http://192.168.0.118:3100/&quot;
});

<!-- end snippet -->

Page to display data: MonsterList.jsx

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

import &quot;./Monsters.css&quot;;
import React, { useEffect, useContext } from &#39;react&#39;;
import MonsterFinder from &quot;../apis/MonsterFinder&quot;;
import { useNavigate, Link } from &quot;react-router-dom&quot;;
import { MonsterContext } from &#39;../context/MonsterContext&#39;;
const MonsterList = (props) =&gt; {
const { monsters, setMonsters } = useContext(MonsterContext);
const navigate = useNavigate()
useEffect(() =&gt; {
const fetchData = async () =&gt; {
try {
const response = await MonsterFinder.get(&quot;/monsters&quot;);
setMonsters(response.data.data.monsters);
} catch (err) {}
};
fetchData();     
}, []);
return (
&lt;div className=&quot;app-container&quot;&gt;
&lt;h1&gt;Monsters&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt; &lt;/th&gt;
&lt;th&gt;Cr&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Alignment&lt;/th&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Info&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
{monsters.map((monster) =&gt; {
return (
&lt;tr&gt;
&lt;td&gt;&lt;img src={require(`../media/${monster.Image}`)} alt={monster.Name} height=&quot;25&quot; width=&quot;25&quot; /&gt;&lt;/td&gt;
&lt;td&gt;{monster.Cr}&lt;/td&gt;
&lt;td&gt;{monster.Name}&lt;/td&gt;
&lt;td&gt;{monster.Source}&lt;/td&gt;
&lt;td&gt;{monster.Type}&lt;/td&gt;
&lt;td&gt;{monster.Size}&lt;/td&gt;
&lt;td&gt;{monster.Alignment}&lt;/td&gt;
&lt;td&gt;{monster.Tag}&lt;/td&gt;
&lt;td&gt;&lt;button className=&quot;button&quot;&gt;&lt;Link className=&quot;links&quot; to={`/monsterinfo/${monster.Name}`}&gt;Info&lt;/Link&gt;&lt;/button&gt;&lt;/td&gt;
&lt;/tr&gt;
);
})}
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
)
};
export default MonsterList

<!-- end snippet -->

In server.js I console.log(results) And the console shows:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

GET /monsters 304 37.024 ms - -
Result {
command: &#39;SELECT&#39;,
rowCount: 2,
oid: null,
rows: [
{
id: 1,
image: &lt;Buffer 69 6d 67 31 2e 6a 70 67&gt;,
table: null,
cr: &#39;1/2&#39;,
source: &#39;Monster Manual&#39;,
type: &#39;Humanoid&#39;,
size: &#39;Medium&#39;,
alignment: &#39;N&#39;,
tags: null,
info: null,
name: &#39;Goblin&#39;
},
{
id: 13,
image: null,
table: null,
cr: &#39;1/4&#39;,
source: &#39;Monster Manual&#39;,
type: &#39;Monster&#39;,
size: &#39;Medium&#39;,
alignment: &#39;N&#39;,
tags: null,
info: null,
name: &#39;Spiderz&#39;
}
],
fields: [
Field {
name: &#39;id&#39;,
tableID: 16391,
columnID: 1,
dataTypeID: 23,
dataTypeSize: 4,
dataTypeModifier: -1,
format: &#39;text&#39;
},
etc

<!-- end snippet -->

So the data is collected but when I inspect the webpage I see just the thead and get:

React没有显示来自express后端的数据

React没有显示来自express后端的数据

And you see the MonsterList Array=(0)

The problem is not in how I get the tbody data showing, it worked when I used a mock_data.json file.

答案1

得分: 1

首先,我想提醒您关于您的"useEffect"钩子,如果您处于开发阶段,React将挂载和卸载您的组件,使您的组件渲染两次,这种行为是为了更好地捕获开发阶段的错误而实施的。了解更多

我认为您之所以收到http 304是因为您的组件在获取数据两次,您的终端点发送304是因为它看到请求相同的有效负载。

您可以使用useRef来解决这个确切的问题,如下所示:

// 我们设置一个ref来在渲染之间保持变量的持久性
const alreadyRunned = useRef(false)

useEffect(() => {
  if (alreadyRunned.current === false) {
    // 我们将"current"属性设置为true,只执行一次useEffect
    alreadyRunned.current = true;

    // 在这里放置您的代码
  }
});
英文:

First of all, i'd like to bring your attention to your "useEffect" hook, if you are in development phase, react will mount and unmount your component, making you component render twice, this behavior was implemented to better catch bugs in dev phase. learn more

I think you are getting http 304 because your component is fetching the data twice, your endpoint is sending 304 because he is seeing the same payload being requested.

You could use the useRef to solve this exact problem, like so:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

// We set a ref to persist a variable between renders
const alreadyRunned = useRef(false)
useEffect(() =&gt; {
if(alreadyRunned.current == false) {
// We set the &quot;current&quot; property to true, to execute only once the useEffect
alreadyRunned.current = true;
// Your code here
}
});

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月16日 17:42:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/75470396.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定