如何获取Redux初始状态副本,点击按钮后重置以实现正确过滤?
问题根源
你当前的核心问题是每次过滤后都直接修改了Redux中存储的博客源数据:用dispatch(setWholeState(filteredBlogs))把Redux的state.blog替换成了过滤后的子集,导致后续再点击过滤按钮时,allBlogs拿到的已经是上次过滤后的结果,而非完整的初始全量数据。
另外你尝试用originalState保存初始状态,但存在两个漏洞:
useMemo依赖为空数组,只会在组件挂载时生成一次副本,若后续Redux中原始博客数据更新,originalState不会同步;- 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
相关产品推荐
相关产品推荐

