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

React页面刷新后代码崩溃,如何通过条件逻辑修复?

修复PostDetail页面刷新崩溃问题

问题原因

刷新PostDetail页面时,ContentContext中的contents初始值为空数组[],此时在PostDetail组件中通过contents.find(post => post.id === id)查找对应帖子会返回undefined。后续代码直接访问post.id、post.title等属性时,就会因post为undefined抛出错误,导致页面崩溃。

解决方案

1. 在PostDetail组件中添加空值检查与加载状态

在组件渲染前先判断post是否存在,不存在时显示加载提示或空白内容,避免直接访问undefined的属性。同时调整依赖于post的逻辑,确保只有post存在时才执行。

修改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: paramsId } = useParams();
    const id = parseInt(paramsId);
    const post = contents.find(post => post.id === id);
    const navigate = useNavigate();
    const [commentMode, setCommentMode] = useState(false);
    const openComment = () => setCommentMode(prev => !prev);
    const [liked, setLiked] = useState(false);
    const params = useParams();

    // 只有post存在时才发起点赞状态请求
    useEffect(() => {
        if (!post) return;
        
        fetch(`/posts/${post.id}/likes`)
        .then(resp => {
            if (resp.ok) {
                resp.json().then(data => {
                    setLiked(data.liked);
                });
            } 
        })
        .catch(errors => {
            setErrors(errors);
        });
    }, [post, setErrors])

    const handleLike = () => {
        if (!post) return;
        
        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 = () => {
        if (!post) return;
        
        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 = () => {
        if (!post) return;
        
        fetch(`/posts/${post.id}`, {
            method: "DELETE",
        })
        .then(resp => resp.json())
        .then(() => deletePost(post.id))
        .then(() => navigate(`/posts`))
    }

    // post不存在时显示加载提示
    if (!post) {
        return <div>加载中...</div>;
    }

    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;

2. 可选:在ContentContext中添加加载状态(优化体验)

为了让所有依赖contents的组件都能感知数据加载状态,可以在ContentContext中添加isLoading状态,统一管理加载逻辑。

修改ContentContext.js:

import { createContext, useContext, useEffect, useState } from "react";
import { ErrorContext } from "./ErrorContext";
import { UserContext } from "./UserContext";

const ContentContext = createContext({});
const ContentProvider = ({children}) => {
    const { setErrors } = useContext(ErrorContext);
    const { loggedIn } = useContext(UserContext);
    const [contents, setContents] = useState([]);
    const [isLoading, setIsLoading] = useState(true); // 添加加载状态

    useEffect(() => {
        setIsLoading(true); // 开始请求时设置为加载中
        fetch('/posts')
        .then(resp => {
            if (resp.ok) {
                resp.json().then(data => {
                    setContents(data);
                });
            }
        })
        .catch(errors => {
            setErrors(errors);
        })
        .finally(() => {
            setIsLoading(false); // 请求结束后关闭加载状态
        });
    }, [setErrors, loggedIn])

    const addPost = (newPost) => {
        setContents([...contents, newPost]);
    }

    const editPost = (newPost) => {
        const updatedContentList = contents.map(post => {
            if (newPost.id === post.id) {
                return newPost
            } else {
                return post;
            }
        });
        setContents(updatedContentList);
    }

    const deletePost = (id) => {
        const updatedContentList = contents.filter(post => post.id !== id)
        setContents(updatedContentList);
    }

    return (
        <ContentContext.Provider value={{ contents, isLoading, addPost, editPost, deletePost }}>{ children }</ContentContext.Provider>
    )
}

export { ContentContext, ContentProvider }

之后在PostDetail中可以使用isLoading状态优化加载提示:

// 在PostDetail中获取isLoading
const { contents, deletePost, isLoading } = useContext(ContentContext);

// ...

if (isLoading || !post) {
    return <div>加载中...</div>;
}

额外修复点

onDeletePost方法中,.then(deletePost(post.id))会立即执行deletePost,而非等待请求完成后执行,需改为箭头函数.then(() => deletePost(post.id)),避免请求未完成时就删除本地数据引发不一致问题。

内容的提问来源于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:18:10