Redux状态重复添加帖子:返回Profile页重复dispatch相同帖子
解决Profile页返回时重复添加帖子到Redux数组的问题
问题根源
- 切换路由返回Profile页时,组件重新挂载,
useGetUserPostsQuery会重新获取数据(或读取缓存),触发useEffect将数据直接追加到userPosts,无去重逻辑导致重复。 postSlice中的updateUserPosts仅做简单的数组push操作,不对已有数据做重复校验。- 离开Profile页时未重置
userPosts状态,再次进入时旧数据保留,新数据继续追加。
方案1:直接使用RTQ缓存,取消手动同步到Redux(推荐)
RTQ本身已内置缓存、请求管理功能,完全没必要将数据同步到自定义Redux切片,这是冗余操作,也是问题的核心诱因。
修改ProfileScreen组件:
import { Link, useLocation } from "react-router-dom"; import Tweets from "../components/Tweets"; import { FaEdit } from "react-icons/fa"; import { useGetUserDetailsQuery } from "../slices/userApiSlice"; import ProfileRightBar from "../components/ProfileRightBar"; import { toast } from "react-toastify"; import Spinner from "../components/Spinner"; import { useEffect, useState, useRef } from "react"; import { useGetUserPostsQuery } from "../slices/postApiSlice"; const ProfileScreen = () => { const [page, setPage] = useState(1); const [hasMore, setHasMore] = useState(true); const lastPostRef = useRef(); const location = useLocation(); const username = location.pathname.split("/")[2]; // 将page作为请求参数传入,实现分页逻辑 const { data: posts, isFetching, isLoading, error } = useGetUserPostsQuery(page); useEffect(() => { error && toast.error(error?.data?.message); }, [error]); useEffect(() => { if (posts) { setHasMore(posts.length > 0); } }, [posts]); useEffect(() => { const observer = new IntersectionObserver( (entries) => { if (entries[0].isIntersecting && !isFetching && hasMore) { setPage(prev => prev + 1); } }, { threshold: 1 } ); lastPostRef.current && observer.observe(lastPostRef.current); return () => observer.disconnect(); }, [isFetching, hasMore]); if (isLoading) return <Spinner />; if (error) return null; return ( <div className="w-full h-screen overflow-scroll"> <div className="flex"> <div className="border-r border-lightgray flex-[0.7] h-screen overflow-auto"> {/* 直接使用RTQ返回的posts数据 */} <Tweets posts={posts || []} /> <div ref={lastPostRef}></div> </div> </div> </div> ); }; export default ProfileScreen;
同时可删除postSlice中的userPosts字段与updateUserPosts方法,减少冗余状态。
方案2:保留自定义Redux,添加去重与状态重置逻辑
若因业务需求必须将帖子存入自定义Redux切片,需做以下修改:
1. 给updateUserPosts添加去重逻辑
修改postSlice,通过帖子唯一标识(如id)过滤重复数据:
const initialState = { posts: [], userPosts: [], }; const postSlice = createSlice({ name: "posts", initialState, reducers: { updateUserPosts: (state, action) => { // 过滤已存在的帖子(假设帖子有唯一id字段) const newPosts = action.payload.filter( post => !state.userPosts.some(item => item.id === post.id) ); state.userPosts.push(...newPosts); }, // 添加重置userPosts的方法 resetUserPosts: state => { state.userPosts = []; } }, }); export const { updateUserPosts, resetUserPosts } = postSlice.actions; export default postSlice.reducer;
2. 组件卸载时重置userPosts
在ProfileScreen中添加卸载清理逻辑:
import { updateUserPosts, resetUserPosts } from "../slices/postSlice"; const ProfileScreen = () => { // ... 其他代码 useEffect(() => { // 离开页面时清空userPosts return () => dispatch(resetUserPosts()); }, [dispatch]); // ... 其他代码 };
3. 完善分页请求参数
确保useGetUserPostsQuery接收page参数,避免每次请求返回重复的第一页数据:
const { data: posts, isFetching, isLoading, error } = useGetUserPostsQuery(page);
内容的提问来源于stack exchange,提问作者user21383275
相关产品推荐
相关产品推荐

