React组件间布尔类型Props传递及骨架屏实现问题
React组件骨架屏实现及布尔Props传递修复
问题定位
- AllPosts.jsx:未将维护的
isPostsLoading状态传递给子组件Posts,导致后续组件无法获取全局加载状态 - Posts.jsx:渲染过滤后的帖子列表时,未给
Post组件传递isPostsLoading属性;同时全局加载状态和搜索加载状态的逻辑边界不清晰 - Post.jsx:缺失
moment和Link的导入;加载状态下返回的骨架结构与实际帖子布局不匹配,且批量生成骨架的逻辑不符合"每个未加载div显示骨架"的需求
修复方案
1. 修改AllPosts.jsx:传递加载状态props
将isPostsLoading作为props传递给Posts组件:
export default function AllPosts() { const [posts, setPosts] = useState([]); const { search } = useLocation(); const [isPostsLoading, setIsPostsLoading] = useState(true); useEffect(() => { const fetchPosts = async () => { const res = await axios.get("/posts" + search); setPosts(res.data); setIsPostsLoading(false); }; fetchPosts(); }, [search]); return ( <> <div className="posts"> <div className="header"> <div className="headerTitle"> <span className="headerTitleLg">المقالات</span> </div> </div> <div className="postsContent"> {/* 传递isPostsLoading给Posts组件 */} <Posts posts={posts} isPostsLoading={isPostsLoading} /> </div> </div> </> ); }
2. 修改Posts.jsx:统一传递加载状态,优化加载逻辑
在渲染过滤结果时也传递isPostsLoading,并调整全局加载状态的显示位置:
import SearchIcon from '@mui/icons-material/Search'; import CircularProgress from '@mui/material/CircularProgress'; import Post from './Post'; // 确保导入Post组件 import { useState } from 'react'; import Box from '@mui/material/Box'; export default function Posts({ posts = [], isPostsLoading}) { const [filteredResults, setFilteredResults] = useState([]); const [searchInput, setSearchInput] = useState(''); const [isSearchLoading, setIsSearchLoading] = useState(false); // 重命名区分搜索加载状态 const filter = (e) => { const keyword = e.target.value; setIsSearchLoading(true); setTimeout(() => { // 模拟搜索延迟,实际场景可移除 if (keyword !== '') { const filteredData = posts.filter((post) => { return Object.values(post) .join('') .toLowerCase() .includes(keyword.toLowerCase()) // 修正搜索条件使用当前输入值 }) setFilteredResults(filteredData) } else { setFilteredResults(posts) } setSearchInput(keyword); setIsSearchLoading(false); }, 300); } // 全局加载时直接显示骨架屏列表 if (isPostsLoading) { return ( <div className="postsBox"> {Array.from({length: 6}).map((_, idx) => ( <Post key={idx} isPostsLoading={true} /> ))} </div> ) } return ( <div className="posts"> <div className="postsContainer"> <div className="postsSearchContainer"> <div className="postsSearch"> <div className="postsSearchIconContainer"> <SearchIcon className="w-5 h-5" /> </div> <input type="text" className="postsSearchInput" placeholder="search" name="postsSearchText" id="postsSearchText" onChange={filter} /> </div> </div> <div className="postsBoxContainer"> <div className="postsBox"> {isSearchLoading ? ( <Box sx={{ display: 'flex', justifyContent: 'center', padding: '2rem' }}> <CircularProgress /> </Box> ) : ( filteredResults.length > 0 ? ( filteredResults.map((filteredPosts) => ( <Post key={filteredPosts._id} post={filteredPosts} isPostsLoading={false} /> )) ) : ( posts.map((post) => ( <Post key={post._id} post={post} isPostsLoading={false} /> )) ) )} </div> </div> </div> </div> ); };
3. 修改Post.jsx:补全依赖,匹配布局的骨架屏
补全缺失的导入,调整骨架结构与实际帖子布局一致,实现单个帖子的骨架效果:
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton' import 'react-loading-skeleton/dist/skeleton.css' import moment from 'moment'; // 补全moment导入 import { Link } from 'react-router-dom'; // 补全Link导入 export default function Post({ post, isPostsLoading }) { // 加载状态下返回单个帖子的骨架 if (isPostsLoading) { return ( <SkeletonTheme color='#F5F5F5' highlightColor='#ffffff'> <div className="post"> <div className="postImg"> <Skeleton width='100%' height={200} /> </div> <div className="postInfo"> <span className="postTitle"> <Skeleton height={30} width='80%' /> </span> <div> <Skeleton count={3} height={16} className="postDesc" /> </div> <span className="postDate"> <Skeleton width={100} height={16} /> </span> </div> </div> </SkeletonTheme> ) } // 非加载状态渲染实际内容 moment.locale('ar'); const daysAgo = moment(post.createdAt); return ( <div className="post"> <div> {post.photo && ( <Link to={`/post/${post._id}`} className="link"> <img className="postImg" src={post.photo} alt="" /> </Link> )} </div> <div className="postInfo"> <Link to={`/post/${post._id}`} className="link"> <span className="postTitle"> {post.title} </span> </Link> <div> <p dir="auto" className="postDesc"> {post.content} </p> </div> <span className="postDate"> {daysAgo.fromNow()} </span> </div> </div> ); }
关键优化点
- 明确区分全局数据加载状态(
isPostsLoading)和搜索加载状态(isSearchLoading),避免逻辑混淆 - 单个
Post组件的骨架结构与实际帖子布局完全匹配,实现"每个未加载div显示骨架"的需求 - 补全所有缺失的依赖导入,消除运行时错误
- 给列表项添加
key属性,符合React列表渲染规范
内容的提问来源于stack exchange,提问作者sultan.h
相关产品推荐
相关产品推荐

