You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 13:48:25