React项目宝可梦列表过滤后组件不重新渲染如何解决?
问题排查与修复方案
你代码里存在两处核心问题导致列表不更新:
1. App组件中useMemo使用错误
你当前的useMemo写法不符合规范:
- 把
_data空数组声明在useMemo外部,还将_data放入依赖数组,会导致缓存逻辑完全失效 - 用
map遍历并往外部数组推送数据的写法冗余,也容易引发引用异常
修正后的App组件对应代码:
import React from "react"; import { types, pokemons } from "./data"; import Avatar from "./components/Avatar"; import List from "./components/List"; import "./styles.css"; const App = () => { const [favorite, setFavorite] = React.useState("rock"); // 直接用useMemo返回过滤去重后的数组,依赖项只放pokemons和favorite const filteredPokemons = React.useMemo(() => { // 先过滤符合类型的宝可梦 const matched = pokemons.filter(pokemon => pokemon.type.includes(favorite.toLowerCase()) ); // 去重逻辑合并到memo里 const nameSet = new Set(); return matched.filter(pokemon => { if (!nameSet.has(pokemon.name)) { nameSet.add(pokemon.name); return true; } return false; }) }, [pokemons, favorite]); return ( <div className="App"> <Avatar data={types} setFavorite={setFavorite} /> <List data={filteredPokemons} /> </div> ); }; export default App;
2. List组件内部state没有同步父组件传参更新
你在List组件中把父组件传的data作为pokemonsState的初始值,但useState的初始值仅在组件第一次挂载时生效,父组件传入的data更新时,内部state不会自动同步。
两种修复方案二选一即可:
方案一:添加监听逻辑同步props
给List组件加useEffect监听data变化,自动更新内部state:
import { useState, useEffect } from 'react'; // 其他导入省略 const List = ({ data }) => { const [pokemonsState, setPokemonsState] = useState(data); const [isAscSort, setIsAscSort] = useState(false); // 新增:监听data和排序规则变化,自动更新列表 useEffect(() => { setPokemonsState(stableSort(data, getComparator(isAscSort ? "asc" : "desc", "name"))); }, [data, isAscSort]) const sortPokemon = () => { setIsAscSort(!isAscSort); }; // 其余渲染逻辑保持不变 };
方案二:删除内部state,直接使用props.data
如果不需要额外缓存逻辑,直接用props的data进行渲染和排序即可,完全避免不同步问题:
// 其他导入省略 const List = ({ data }) => { const [isAscSort, setIsAscSort] = useState(false); // 每次渲染直接根据当前排序规则处理data const sortedPokemons = stableSort(data, getComparator(isAscSort ? "asc" : "desc", "name")); const sortPokemon = () => { setIsAscSort(!isAscSort); }; return ( <TableContainer> <Table sx={{ minWidth: 650 }}> <TableHead> <TableRow> <TableCell>Pokémon</TableCell> <TableCell name onClick={() => sortPokemon()} align="right"> Name {!isAscSort ? <ArrowUpward /> : <ArrowDownward />} </TableCell> </TableRow> </TableHead> <TableBody> {/* 直接用sortedPokemons渲染 */} {sortedPokemons.map((pokemon, idx) => ( <TableRow key={idx} sx={{ "&:last-child td, &:last-child th": { border: 0 } }} > <TableCell component="th" scope="row" thumbnailImage> <div className="thumb"> <img src={pokemon.thumbnailImage} alt="" /> </div> </TableCell> <TableCell align="left" component="th" scope="row" description> {pokemon.name} </TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> ); };
修改以上两处问题后,点击类型切换时列表就会正常更新。
内容的提问来源于stack exchange,提问作者Tainara
相关产品推荐
相关产品推荐

