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

React帖子详情页刷新时post属性未定义的问题求助

刷新React帖子详情页时出现post.id未定义错误

我正在开发一个支持用户发布帖子、评论、点赞/取消点赞的React应用,正常跳转进入帖子详情页一切正常,但刷新页面时会出现post.id未定义的错误,移除post.id引用后又会出现post.title未定义,以此类推。附上App.js和PostDetail.js代码,求解决方法。


App.js代码

import './App.css';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Navbar from './pages/Navbar';
import LoginPage from './pages/LoginPage';
import PostList from './posts/PostList';
import PostDetail from './posts/PostDetail';
import EditPost from './posts/EditPost';
import Home from './pages/Home';

function App() {
  return (
    <BrowserRouter>
    <Navbar />
    <div className="App">
      <Routes>
        <Route path="/posts" element={<PostList />} />
        <Route path="/posts/:id/edit" element={<EditPost/>} />
        <Route path="/posts/:id" element={<PostDetail />} />
        <Route path="/home" element={<Home />} />
        <Route path="/" element={<LoginPage />} />
      </Routes>
    </div>
    </BrowserRouter>
  );
}

export default App;

PostDetail.js代码

import { useContext, useEffect, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import { ContentContext } from "../context/ContentContext";
import { UserContext} from "../context/UserContext";
import CommentList from "../comments/CommentList";
import { ErrorContext } from "../context/ErrorContext";

function PostDetail () {
    const { setErrors } = useContext(ErrorContext);
    const { user } = useContext(UserContext);
    const { contents, deletePost } = useContext(ContentContext);
    const id = parseInt(useParams().id);
    const post = contents.find(post => post.id === id);
    const navigate = useNavigate();
    const [commentMode, setCommentMode] = useState(false);
    const openComment = () => setCommentMode(commentMode => !commentMode);
    const [liked, setLiked] = useState(false);
    const params = useParams();

    useEffect(() => {
        fetch(`/posts/${post.id}/likes`)
        .then(resp => {
            if (resp.ok) {
                resp.json().then(data => {
                    setLiked(data.liked)
                })
            }
        })
        .catch(error => {
            setErrors(error)
        })
    }, [post, setErrors])

    const handleLike = () => {
        fetch(`/posts/${post.id}/likes`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
        })
        .then(resp => resp.json())
        .then(data => {
            if (data.success) {
                setLiked(true);
            }
        })
        .catch(error => {
            setErrors(error)
        });
    }

    const handleUnlike = () => {
        fetch(`/posts/${post.id}/likes/${params.id}`, {
            method: 'DELETE',
            headers: {
                'Content-Type': 'application/json',
            },
        })
        .then(resp => resp.json())
        .then(data => {
            if (data.success) {
                setLiked(false);
            }
        })
        .catch(error => {
            setErrors(error)
        });
    }

    const onDeletePost = () => {
        fetch(`/posts/${post.id}`, {
            method: "DELETE",
        })
        .then(resp => resp.json())
        .then(deletePost(post.id))
        .then(navigate(`/posts`))
    }

    return (
        <div>
            <div className="box-2">
                <h1>{post.title}</h1>
                <h5>{post.creator.username}</h5>
                <p>{post.content}</p>
                {liked ? (
                    <button className="edit-btn" onClick={handleUnlike}>Unlike</button>
                ):(
                    <button className="edit-btn" onClick={handleLike}>Like</button>
                )}
                <button className="edit-btn" onClick={openComment}>Comments</button>
                {user && user.username === post.creator?.username && (
                    <>
                    <button className="edit-btn"><Link to={`/posts/${post.id}/edit`}>Edit</Link></button>
                    <button className="edit-btn" onClick={onDeletePost}>Delete</button>
                    </>
                )}
                <br /><br />
            </div>
            <br />
            <hr />
            <br />
            <div>
                {commentMode && <CommentList post={post}/>}
            </div>
        </div>
    )
}

export default PostDetail;

问题原因&解决方法

核心原因

刷新页面时,全局ContentContext中的contents数组还没完成初始化(或者是空的),此时contents.find()找不到对应帖子,返回undefined,直接访问post.id、post.title这类属性就会触发未定义错误。

1. 快速修复:添加空状态判断

在PostDetail组件的return语句上方,先判断post是否存在,不存在时显示加载提示:

// 放在return语句上方
if (!post) {
  return <div>加载中...</div>;
}

2. 彻底解决:优化数据获取逻辑

依赖全局Context的缓存数据在刷新时会丢失,更可靠的方式是在PostDetail组件中单独请求当前帖子的数据,不依赖全局缓存:

// 修改PostDetail的核心逻辑
function PostDetail () {
    const { setErrors } = useContext(ErrorContext);
    const { user } = useContext(UserContext);
    const { deletePost } = useContext(ContentContext);
    const { id } = useParams();
    const numericId = parseInt(id);
    const [post, setPost] = useState(null);
    const navigate = useNavigate();
    const [commentMode, setCommentMode] = useState(false);
    const [liked, setLiked] = useState(false);

    // 单独请求当前帖子数据
    useEffect(() => {
        fetch(`/posts/${numericId}`)
            .then(resp => resp.json())
            .then(data => setPost(data))
            .catch(error => setErrors(error));
    }, [numericId, setErrors]);

    // 等post加载完成后再请求点赞状态
    useEffect(() => {
        if (!post) return;
        fetch(`/posts/${post.id}/likes`)
            .then(resp => {
                if (resp.ok) {
                    resp.json().then(data => setLiked(data.liked))
                }
            })
            .catch(error => setErrors(error))
    }, [post, setErrors])

    // 空状态判断
    if (!post) {
        return <div>加载中...</div>;
    }

    // 其余handleLike、handleUnlike等逻辑保留,注意修复以下小问题
}

3. 修复其他细节错误

  • handleUnlike路径错误:当前路径是/posts/${post.id}/likes/${params.id},这里的params.id是帖子ID,需替换为点赞记录ID;如果后端接口支持根据用户+帖子ID取消点赞,可改为/posts/${post.id}/likes
  • onDeletePost链式调用错误:then(deletePost(post.id))会直接执行函数,需改成回调形式:
.then(() => deletePost(post.id))
.then(() => navigate(`/posts`))

内容的提问来源于stack exchange,提问作者janestack

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 06:13:10