React Redux与WordPress API:如何从Redux Store加载单篇文章?
嘿,我来帮你搞定单篇文章的渲染问题!既然你已经能顺利获取多篇WordPress文章并存进Redux Store,那距离实现单篇渲染其实只差几步关键操作,咱们一步步拆解:
1. 给单页路由添加动态文章ID参数
首先得让你的路由能识别单篇文章的唯一标识——也就是WordPress返回的文章ID。用React Router的话,只要在路由路径里加上:postId这个动态参数就行,这样用户访问/posts/123这类URL时,我们就能拿到123这个ID:
// 比如在App.js的路由配置里 import { Routes, Route } from 'react-router-dom'; import PostList from './components/PostList'; import SinglePost from './components/SinglePost'; function App() { return ( <Routes> <Route path="/" element={<PostList />} /> {/* :postId就是动态参数,用来匹配具体的文章ID */} <Route path="/posts/:postId" element={<SinglePost />} /> </Routes> ); }
2. 在单篇文章组件中获取URL里的ID
接下来在SinglePost组件里,用React Router的useParams钩子把URL里的postId取出来。注意要转成数字类型,因为WordPress返回的文章ID是数字:
// SinglePost.js import { useParams } from 'react-router-dom'; import { useSelector } from 'react-redux'; function SinglePost() { // 从URL提取postId参数 const { postId } = useParams(); // 转成数字,避免字符串和数字匹配失败 const numericPostId = parseInt(postId, 10); // 从Redux Store里拿到之前存的所有文章列表 const allPosts = useSelector(state => state.posts.postsList);
3. 从Store的文章列表中筛选目标文章
拿到ID之后,用数组的find方法就能从所有文章里精准定位到我们要的那一篇:
// 筛选出ID匹配的单篇文章 const targetPost = allPosts.find(post => post.id === numericPostId); // 处理文章还没加载到Store的情况(比如用户直接访问单页URL) if (!targetPost) { return <div>加载中...</div>; }
4. 渲染单篇文章的内容
现在就可以把targetPost里的字段渲染出来了!注意WordPress返回的文章内容是HTML格式,需要用dangerouslySetInnerHTML来渲染:
return ( <div className="single-post-container"> <h1>{targetPost.title.rendered}</h1> <p className="post-meta"> 发布于: {new Date(targetPost.date).toLocaleDateString()} </p> {/* 渲染文章内容,__html对应WordPress返回的content.rendered */} <div className="post-content" dangerouslySetInnerHTML={{ __html: targetPost.content.rendered }} /> </div> ); } export default SinglePost;
额外优化:直接请求单篇文章(防止用户直接访问单页)
如果用户直接输入单篇文章的URL,这时候Store里可能还没有这篇文章,我们可以在组件里判断,要是没找到就直接调用WordPress API获取单篇:
// 在SinglePost组件里补充代码 import { useDispatch } from 'react-redux'; import { fetchSinglePost } from '../actions/postActions'; import { useEffect } from 'react'; function SinglePost() { const { postId } = useParams(); const numericPostId = parseInt(postId, 10); const allPosts = useSelector(state => state.posts.postsList); const targetPost = allPosts.find(post => post.id === numericPostId); const isLoading = useSelector(state => state.posts.isLoading); const dispatch = useDispatch(); // 组件挂载时检查,没有目标文章就请求API useEffect(() => { if (!targetPost) { dispatch(fetchSinglePost(numericPostId)); } }, [dispatch, numericPostId, targetPost]); // 处理加载状态 if (isLoading) { return <div>正在加载文章...</div>; } // 处理文章不存在的情况 if (!targetPost) { return <div>抱歉,这篇文章不存在😢</div>; } // 渲染内容... }
对应的action和reducer也要处理单篇请求的逻辑:
// actions/postActions.js export const fetchSinglePost = (postId) => async (dispatch) => { dispatch({ type: 'FETCH_SINGLE_POST_REQUEST' }); try { // 调用WordPress单篇文章API const res = await fetch(`https://你的WordPress地址/wp-json/wp/v2/posts/${postId}`); const post = await res.json(); // 把获取到的文章加到Store的列表里,同时存为单篇文章 dispatch({ type: 'FETCH_SINGLE_POST_SUCCESS', payload: post }); } catch (err) { dispatch({ type: 'FETCH_SINGLE_POST_FAILURE', payload: err.message }); } };
// reducers/postReducer.js const initialState = { postsList: [], singlePost: null, isLoading: false, error: null }; const postReducer = (state = initialState, action) => { switch (action.type) { case 'FETCH_SINGLE_POST_REQUEST': return { ...state, isLoading: true }; case 'FETCH_SINGLE_POST_SUCCESS': // 避免重复添加相同文章到列表 const updatedPosts = state.postsList.some(p => p.id === action.payload.id) ? state.postsList : [...state.postsList, action.payload]; return { ...state, isLoading: false, postsList: updatedPosts, singlePost: action.payload }; case 'FETCH_SINGLE_POST_FAILURE': return { ...state, isLoading: false, error: action.payload }; // 保留你之前处理多篇文章的逻辑 default: return state; } }; export default postReducer;
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

