React中API获取的Slug数据无法在前端页面显示求助
React页面无法渲染API获取的Slug详情数据
确认React代码逻辑无问题,在useEffect钩子中打印API返回结果能看到完整数据,但HTML模板中使用这些数据时完全不显示。更奇怪的是这段代码曾短暂正常运行,之后就彻底无法展示详情内容。
前端代码
import React, { useContext, useEffect, useReducer, useRef, useState, } from 'react'; import { Link, useParams } from 'react-router-dom'; import axios from 'axios'; import { API_URL, getError } from '../utils'; import { Store } from '../Store'; import { toast } from 'react-toastify'; import moment from 'moment'; import MessageBox from './MessageBox'; import { Button } from 'react-bootstrap'; import LoadingBox from './LoadingBox'; const reducer = (state, action) => { switch (action.type) { case 'FETCH_REQUEST': return { ...state, loading: true }; case 'FETCH_SUCCESS': return { ...state, blog: action.payload, loading: false }; case 'FETCH_FAIL': return { ...state, loading: false, error: action.payload }; default: return state; } }; export default function BlogpostScreen() { let reviewsRef = useRef(); const [comment, setComment] = useState(''); const params = useParams(); const { slug } = params; const [{ loading, error, blog }, dispatch] = useReducer( reducer, { blog: {}, loading: true, error: '', } ); useEffect(() => { const fetchData = async () => { dispatch({ type: 'FETCH_REQUEST' }); try { const result = await axios.get(`${API_URL}/api/blogs/slug/${slug}`); dispatch({ type: 'FETCH_SUCCESS', payload: result.data }); } catch (err) { dispatch({ type: 'FETCH_FAIL', payload: getError(err.message) }); } }; fetchData(); }, [slug]); const { state } = useContext(Store); const { userInfo } = state; return ( <div className="position-relative mb-3"> <img className="img-fluid w-100" src={blog.image} alt={blog.name} style={{ objectFit: 'cover' }} /> <div className="bg-white border border-top-0 p-4"> <div className="mb-3"> <Link className="badge badge-primary text-uppercase font-weight-semi-bold p-2 mr-2" to={{ pathname: '/search', search: `category=${blog.category}`, }} > {blog.category} </Link> <a className="text-body" href="/"> {moment(blog.createdAt).format('MMMM Do YYYY, h:mm:ss a')} </a> </div> <h1 className="mb-3 text-secondary text-uppercase font-weight-bold"> {blog.name} </h1> <div dangerouslySetInnerHTML={{ __html: blog.post }}></div> </div> <div className="d-flex justify-content-between bg-white border border-top-0 p-4"> <div className="d-flex align-items-center"> <img className="rounded-circle mr-2" src="img/user.jpg" width="25" height="25" alt="" /> <span>KimmoTech</span> </div> <div className="d-flex align-items-center"> <span className="ml-3"> <i className="far fa-eye mr-2"></i> {blog.views} </span> <span className="ml-3"> <i className="far fa-comment mr-2"></i> {blog.numReviews} </span> </div> </div> </div> ); }
后端代码
blogRouter.get('/slug/:slug', async (req, res) => { const blog = await Blog.findOneAndUpdate( { slug: req.params.slug }, { $inc: { views: 1 } }, { new: true } ); if (blog) { res.send({blog}); } else { res.status(404).sendStatus({ message: 'Blogpost Not Found' }); } });
问题根源与修复方案
核心问题:数据嵌套层级不匹配
后端接口返回的是嵌套对象:res.send({blog}) 等价于返回 { blog: 实际博客数据 },但前端在reducer的FETCH_SUCCESS中直接将blog状态设为action.payload(即整个嵌套对象),导致页面中blog.name、blog.image等属性实际为undefined(正确路径应为blog.blog.name)。
修复方案二选一:
- 方案1:修正前端reducer
修改FETCH_SUCCESS的payload赋值,取嵌套的blog字段:case 'FETCH_SUCCESS': return { ...state, blog: action.payload.blog, loading: false }; - 方案2:修正后端接口
直接返回博客数据对象,不需要额外嵌套,同时修正404返回的错误写法:if (blog) { res.send(blog); // 去掉外层的{blog}包裹 } else { res.status(404).send({ message: 'Blogpost Not Found' }); // sendStatus仅传状态码,改为send传错误对象 }
额外优化:完善加载/错误状态处理
当前代码未在页面中处理loading和error状态,初始加载时会显示空内容,建议在返回的JSX最外层添加:
if (loading) { return <LoadingBox />; } if (error) { return <MessageBox variant="danger">{error}</MessageBox>; }
内容的提问来源于stack exchange,提问作者Chidimma Nworah
相关产品推荐
相关产品推荐

