通过ID数组渲染对象数组元素:TypeScript报错与最佳实践
问题解答
1. 问题出在哪里?
你的两段代码都存在逻辑错误,导致TypeScript报错:
第一段代码的问题
你完全误用了filter的作用:filter是用来筛选数组元素的,回调函数必须返回布尔值,但你在回调里返回了<li>{book.title}</li>这种JSX元素,根本起不到筛选作用。同时map函数内部没有返回filter的结果,最终renderBooks()返回的是全为undefined的数组,React无法渲染;就算补上return,filter返回数组,map会生成二维数组,也不符合<ul>子元素的要求。
第二段简化代码的问题
renderArray()返回的是fakeObj类型的对象数组,但<ul>的子元素必须是有效的React元素(比如<li>),直接渲染普通对象会触发TypeScript类型检查错误——React无法识别并渲染普通对象。
2. 存储ID还是完整书籍?
推荐存储书籍ID,原因如下:
- 数据一致性:如果目录里的书籍信息(如标题、作者)更新,通过ID匹配能自动获取最新数据,无需额外维护收藏列表里的冗余数据。
- 状态体积小:存储ID数组比存储完整书籍对象节省内存,尤其当书籍数量较多时。
- 符合Redux最佳实践:Redux官方推荐使用归一化状态结构,将不同实体(如书籍、用户收藏)分开存储,通过ID关联,避免数据冗余。
如果存储完整书籍,会带来状态冗余、数据同步麻烦的问题——目录书籍更新后,需手动同步收藏列表里的对应数据,增加代码复杂度。
3. 存储ID时渲染列表的最佳实践
核心思路是先把书籍列表转成以ID为键的查找表,通过ID查找书籍的效率为O(1),远高于每次filter的O(n),同时避免嵌套数组问题。
修正后的第一段代码
const Wishlist = () => { const dispatch = useAppDispatch(); const wishlist = useAppSelector(state => state.user.userInfo.wishlist); const bookList = useAppSelector(state => state.catalogue.list); // 把书籍列表转成查找表:{ [bookId]: book },用useMemo缓存避免重复生成 const bookLookup = useMemo(() => { return bookList.reduce((acc, book) => { acc[book.id] = book; return acc; }, {} as Record<string, typeof bookList[0]>); }, [bookList]); return ( <ul> {wishlist.map(wishId => { const book = bookLookup[wishId]; // 处理书籍不存在的边界情况(如ID无效或书籍已删除) if (!book) return null; return <li key={wishId}>{book.title}</li>; })} </ul> ); }; export default Wishlist;
修正后的第二段简化代码
interface FakeObj { id: string; name: string; } const fakeIds = ['5', '12', '878']; const fakeList: FakeObj[] = [ { id: '334', name: 'Tony' }, { id: '5', name: 'Milly' }, { id: '12', name: 'Jack' }, { id: '7', name: 'Stew' }, { id: '878', name: 'Mark' }, { id: '87998', name: 'Greg' } ]; // 转成查找表 const objLookup = fakeList.reduce((acc, obj) => { acc[obj.id] = obj; return acc; }, {} as Record<string, FakeObj>); return ( <ul> {fakeIds.map(id => { const obj = objLookup[id]; if (!obj) return null; return <li key={id}>{obj.name}</li>; })} </ul> );
关键优化点:
- 用
useMemo缓存查找表,仅在书籍列表变化时重新生成,避免不必要的渲染 - 给每个
<li>添加唯一key(用书籍ID即可),符合React列表渲染要求 - 处理书籍不存在的边界情况,避免渲染错误
内容的提问来源于stack exchange,提问作者ncasteln
相关产品推荐
相关产品推荐

