不起作用"/>
React Server Side Rendering API 数据映射不起作用
我有一个 React 网站并使用服务器端渲染。我的网页显示在浏览器的页面源中,也显示在网页上。 API 数据除外。这仅显示在页面源中,而不显示在网页上。我收到错误消息:Uncaught TypeError: Cannot read properties of undefined (reading 'map')
我这里曾经有 server.js,我在其中获取 API 数据,然后将其传递给适当的组件。这也能正常工作,因为如果我执行 console.log(data),那么该数据也会显示在控制台中。但它们没有映射。
Leistungen.jsx
import React, { useState, useEffect } from 'react';
import { LeistungenContainer, LeistungenHeadline, LeistungenText, LeistungenKasten, TextLink, KastenLink, Titel, Headline, Text, Button } from './Leistungen.elements'
import { FaSign } from 'react-icons/fa'
import { TiBusinessCard } from 'react-icons/ti'
import { GiPapers } from 'react-icons/gi'
import { AiTwotoneBoxPlot } from 'react-icons/ai'
import { BsBoxFill } from 'react-icons/bs'
const leistungenIconsLinks = [
{Leistungsart: "Werbeanlagen & Beschilderung", icon: <FaSign size={50} color="white"/>, link: "/werbeanlagen"},
{Leistungsart: "Werbeartikel", icon: <TiBusinessCard size={50} color="white"/>, link: "/werbeartikel"},
{Leistungsart: "Folierung & Drucken", icon: <GiPapers size={50} color="white"/>, link: "/folierung"},
{Leistungsart: "Verschiedene Banner", icon: <AiTwotoneBoxPlot size={50} color="white"/>, link: "/banner"},
{Leistungsart: "Leuchtkasten & Leuchtreklame", icon: <BsBoxFill size={50} color="white"/>, link: "/leuchtkasten"}
];
const Leistungen = ({data}) => {
return (
<>
<LeistungenContainer>
<LeistungenHeadline>
<Headline>Unsere<br /><span>Leistungen</span></Headline>
<LeistungenText>Test</LeistungenText>
</LeistungenHeadline>
{data.map((leistung, i) => {
const iconLink = leistungenIconsLinks.find(item => item.Leistungsart === leistung.attributes.Leistungsname);
return (
<LeistungenKasten>
<KastenLink to={iconLink.link}>
{iconLink.icon}
<Titel>{leistung.attributes.Leistungsname}</Titel>
<Text>{leistung.attributes.Leistungsbeschreibung}</Text>
<Button to={iconLink.link}>Erfahre mehr</Button>
</KastenLink>
</LeistungenKasten>
);
})}
</LeistungenContainer>
</>
)
}
export default Leistungen
server.js
import fs from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import express from 'express'
import { Helmet } from 'react-helmet';
import fetch from 'node-fetch';
import https from 'https'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const isTest = process.env.VITEST
export async function createServer(
root = process.cwd(),
isProd = process.env.NODE_ENV === 'production',
hmrPort,
) {
const resolve = (p) => path.resolve(__dirname, p)
const indexProd = isProd
? fs.readFileSync(resolve('dist/client/index.html'), 'utf-8')
: ''
const app = express()
/**
* @type {import('vite').ViteDevServer}
*/
let vite
if (!isProd) {
vite = await (
await import('vite')
).createServer({
root,
logLevel: isTest ? 'error' : 'info',
server: {
middlewareMode: true,
watch: {
// During tests we edit the files too fast and sometimes chokidar
// misses change events, so enforce polling for consistency
usePolling: true,
interval: 100,
},
hmr: {
port: hmrPort,
},
},
appType: 'custom',
})
// use vite's connect instance as middleware
app.use(vite.middlewares)
} else {
app.use((await import('compression')).default())
app.use(
(await import('serve-static')).default(resolve('dist/client'), {
index: false,
}),
)
}
const agent = new https.Agent({
rejectUnauthorized: false
});
app.use('*', async (req, res) => {
try {
const url = req.originalUrl
let template, render
if (!isProd) {
// always read fresh template in dev
template = fs.readFileSync(resolve('index.html'), 'utf-8')
template = await vite.transformIndexHtml(url, template)
render = (await vite.ssrLoadModule('/src/entry-server.jsx')).render
} else {
template = indexProd
// @ts-ignore
render = (await import('./dist/server/entry-server.js')).render
}
const context = {}
const response = await fetch('', { agent });
const data = (await response.json()).data;
const appHtml = render(url, context, data);
const helmet = Helmet.renderStatic();
if (context.url) {
// Somewhere a `<Redirect>` was rendered
return res.redirect(301, context.url)
}
const html = template
.replace(`<!--app-html-->`, appHtml)
.replace(`<!--app-head-->`, `${helmet.title.toString()}${helmet.meta.toString()}`)
res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
} catch (e) {
!isProd && vite.ssrFixStacktrace(e)
console.log(e.stack)
res.status(500).end(e.stack)
}
})
return { app, vite }
}
if (!isTest) {
createServer().then(({ app }) =>
app.listen(5175, () => {
console.log('http://localhost:5175')
}),
)
}
回答如下:
传递给 Leistungen 组件的
data
参数到底是什么?情况可能是,随着状态的变化,在某个时候 undefined
被传递给它。最简单的解决方案是像这样使用可选链接(问号运算符):
data?.map(leistung, i) => { ...
这确保了
map
仅在data
不是未定义/空时被调用。但是,更好的解决方案是在数据不可用时呈现类似 Loading
组件的内容。
data ? data.map((leistung, i) => { ...your code here }) : <Loading />
更多推荐
React Server Side Rendering API 数据映射不起作用
发布评论