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

如何获取Redux初始状态副本,点击按钮后重置以实现正确过滤?

问题根源

你当前的核心问题是每次过滤后都直接修改了Redux中存储的博客源数据:用dispatch(setWholeState(filteredBlogs))把Redux的state.blog替换成了过滤后的子集,导致后续再点击过滤按钮时,allBlogs拿到的已经是上次过滤后的结果,而非完整的初始全量数据。

另外你尝试用originalState保存初始状态,但存在两个漏洞:

  1. useMemo依赖为空数组,只会在组件挂载时生成一次副本,若后续Redux中原始博客数据更新,originalState不会同步;
  2. Redux状态更新是异步的,useEffect中先dispatch重置状态,再执行过滤逻辑时,allBlogs还是之前的过滤后数据,过滤依然基于子集。
解决方案

推荐两种可行的修复方式,按需选择:

方案一:Redux拆分状态(更规范)

在Redux切片中分开存储原始全量博客和过滤后展示博客,过滤操作只修改展示状态,不碰原始数据,从根源避免源数据被篡改。

1. 修改Redux切片

import { createSlice } from '@reduxjs/toolkit';

const blogSlice = createSlice({
  name: 'blog',
  initialState: {
    originalBlogs: {}, // 存储完整的原始博客数据
    filteredBlogs: {}  // 存储当前过滤后的展示数据
  },
  reducers: {
    // 设置原始全量博客,初始化时同步到过滤状态
    setOriginalBlogs: (state, action) => {
      state.originalBlogs = action.payload;
      state.filteredBlogs = action.payload;
    },
    // 更新过滤后的展示数据
    setFilteredBlogs: (state, action) => {
      state.filteredBlogs = action.payload;
    }
  }
});

export const { setOriginalBlogs, setFilteredBlogs } = blogSlice.actions;
export default blogSlice.reducer;

2. 修改组件逻辑

const originalBlogs = useSelector((state) => state.blog.originalBlogs);
const filteredBlogs = useSelector((state) => state.blog.filteredBlogs);
const myBlogs = useSelector((state) => state.user.blogs);
const [filter, setFilter] = useState("");
const [navFilterLoading, setNavFilterLoading] = useState(false);

useEffect(() => {
  setNavFilterLoading(true);
  let filteredResult = [];
  const keys = Object.keys(originalBlogs);

  if (filter.startsWith("nat")) {
    filteredResult = keys
      .filter(key => originalBlogs[key].tags.some(tag => tag.startsWith("nat")))
      .map((key, index) => ({ index, ...originalBlogs[key] }));
  } else if (filter.startsWith("tech")) {
    filteredResult = keys
      .filter(key => originalBlogs[key].tags.some(tag => tag.startsWith("tech")))
      .map((key, index) => ({ index, ...originalBlogs[key] }));
  } else if (filter.startsWith("edu")) {
    filteredResult = keys
      .filter(key => originalBlogs[key].tags.some(tag => tag.startsWith("edu")))
      .map((key, index) => ({ index, ...originalBlogs[key] }));
  } else {
    filteredResult = keys.map((key, index) => ({ index, ...originalBlogs[key] }));
  }

  dispatch(setFilteredBlogs(filteredResult));
  setNavFilterLoading(false);
}, [filter, originalBlogs, dispatch]);

方案二:组件内缓存原始数据(快速修复)

如果不想修改Redux结构,可在组件内实时缓存原始全量数据,过滤逻辑始终基于这个缓存副本,而非被修改后的Redux状态。

const allBlogs = useSelector((state) => state.blog);
const myBlogs = useSelector((state) => state.user.blogs);
const [filter, setFilter] = useState("");
const [navFilterLoading, setNavFilterLoading] = useState(false);

// 实时缓存原始全量博客,当Redux中博客数据更新时同步更新副本
const originalBlogs = useMemo(() => JSON.parse(JSON.stringify(allBlogs)), [allBlogs]);

useEffect(() => {
  setNavFilterLoading(true);
  let filteredBlogs = [];
  const keys = Object.keys(originalBlogs);

  if (filter.startsWith("nat")) {
    filteredBlogs = keys
      .filter(key => originalBlogs[key].tags.some(tag => tag.startsWith("nat")))
      .map((key, index) => ({ index, ...originalBlogs[key] }));
  } else if (filter.startsWith("tech")) {
    filteredBlogs = keys
      .filter(key => originalBlogs[key].tags.some(tag => tag.startsWith("tech")))
      .map((key, index) => ({ index, ...originalBlogs[key] }));
  } else if (filter.startsWith("edu")) {
    filteredBlogs = keys
      .filter(key => originalBlogs[key].tags.some(tag => tag.startsWith("edu")))
      .map((key, index) => ({ index, ...originalBlogs[key] }));
  } else {
    filteredBlogs = keys.map((key, index) => ({ index, ...originalBlogs[key] }));
  }

  dispatch(setWholeState(filteredBlogs));
  setNavFilterLoading(false);
}, [filter, originalBlogs, dispatch]);

内容的提问来源于stack exchange,提问作者mozart

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 07:01:06