React+TS+Redux版Rick and Morty应用:实时筛选异常修复求助
解决方案:Rick and Morty 角色展示应用问题修复
1. Redux 状态结构拆分
先把状态拆分成全量角色池和筛选结果集,避免筛选操作污染原始数据,同时保留搜索关键词、加载状态和当前页码:
interface CharacterState { allCharacters: Character[]; // 仅在搜索为空+滚动时新增角色 filteredCharacters: Character[]; // 实时筛选后的展示数据 searchQuery: string; isLoading: boolean; currentPage: number; } // 初始状态 const initialState: CharacterState = { allCharacters: [], filteredCharacters: [], searchQuery: '', isLoading: false, currentPage: 1, };
2. 修正无限滚动触发条件
只有当搜索框为空且未在加载中时,才触发下一页数据加载,避免筛选时误加载:
// 组件内的滚动监听逻辑 useEffect(() => { const handleScroll = () => { const { scrollTop, clientHeight, scrollHeight } = document.documentElement; // 触底阈值200px,仅搜索为空时加载 if (scrollTop + clientHeight >= scrollHeight - 200 && !isLoading && searchQuery === '') { dispatch(fetchNextPageCharacters()); } }; window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, [isLoading, searchQuery, dispatch]);
3. Redux 异步加载与去重逻辑
在加载新角色后,先通过id去重(API返回的角色id唯一),再合并到全量数组;同时只有搜索为空时,同步更新筛选结果:
// 异步加载action export const fetchNextPageCharacters = createAsyncThunk( 'characters/fetchNextPage', async (_, { getState }) => { const state = getState() as RootState; const res = await fetch(`https://rickandmortyapi.com/api/character?page=${state.characters.currentPage + 1}`); const data = await res.json(); return data.results; } ); // Reducer处理逻辑 extraReducers: (builder) => { builder .addCase(fetchNextPageCharacters.pending, (state) => { state.isLoading = true; }) .addCase(fetchNextPageCharacters.fulfilled, (state, action) => { // 基于id去重,避免重复添加 const uniqueNewChars = action.payload.filter( newChar => !state.allCharacters.some(char => char.id === newChar.id) ); state.allCharacters = [...state.allCharacters, ...uniqueNewChars]; state.currentPage += 1; state.isLoading = false; // 搜索为空时,同步筛选结果为全量数据 if (state.searchQuery === '') { state.filteredCharacters = state.allCharacters; } }) .addCase(fetchNextPageCharacters.rejected, (state) => { state.isLoading = false; }); }
4. 实时筛选逻辑实现
添加搜索关键词变更的action,基于全量角色池实时生成筛选结果,清空搜索框时自动恢复全量数据:
// 设置搜索关键词的action export const setSearchQuery = createAction<string>('characters/setSearchQuery'); // Reducer处理筛选 builder.addCase(setSearchQuery, (state, action) => { state.searchQuery = action.payload; // 根据关键词筛选全量角色 if (action.payload.trim() === '') { state.filteredCharacters = state.allCharacters; } else { const query = action.payload.toLowerCase(); state.filteredCharacters = state.allCharacters.filter(char => char.name.toLowerCase().includes(query) ); } });
组件内绑定搜索框:
<input type="text" value={searchQuery} onChange={(e) => dispatch(setSearchQuery(e.target.value))} placeholder="搜索角色名称..." />
5. 列表Key优化
直接用角色的id作为列表key(API返回的唯一标识),比随机key更稳定:
{filteredCharacters.map(char => ( <CharacterCard key={char.id} character={char} /> ))}
如果有特殊场景需要额外随机值,可结合id生成:key={${char.id}-${Math.random()}},但优先使用纯id。
内容的提问来源于stack exchange,提问作者Imaginario27
相关产品推荐
相关产品推荐

