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
相关产品推荐
相关产品推荐

