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

Redux状态重复添加帖子:返回Profile页重复dispatch相同帖子

解决Profile页返回时重复添加帖子到Redux数组的问题

问题根源

  1. 切换路由返回Profile页时,组件重新挂载,useGetUserPostsQuery会重新获取数据(或读取缓存),触发useEffect将数据直接追加到userPosts,无去重逻辑导致重复。
  2. postSlice中的updateUserPosts仅做简单的数组push操作,不对已有数据做重复校验。
  3. 离开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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 20:35:07