====== 第九章:列表渲染 ====== ===== 9.1 基础列表渲染 ===== 使用 JavaScript 的 map 方法将数组转换为元素列表。 function NumberList({ numbers }) { const listItems = numbers.map((number) =>
  • {number}
  • ); return ; } // 更简洁的写法 function NumberList({ numbers }) { return ( ); } // 使用 const numbers = [1, 2, 3, 4, 5];
    ===== 9.2 Key 的重要性 ===== Key 帮助 React 识别哪些元素改变了、添加了或删除了。 function TodoList({ todos }) { return ( ; ); } **选择 Key 的最佳实践**: * 使用数据中的唯一标识(如 ID) * 避免使用数组索引(除非列表不会重新排序) * 保持 Key 在同一兄弟元素中唯一 **为什么不能用索引作为 Key**: // 错误示例 function List({ items }) { return ( ; ); } // 问题:删除第一个元素后,所有元素的 key 都变了 // 导致 React 重新渲染所有输入框,丢失焦点状态 ===== 9.3 提取列表组件 ===== function ListItem({ item }) { return
  • {item.text}
  • ; } function TodoList({ todos }) { return ( ; ); }
    **注意**:key 应该放在数组上下文的元素上,而不是组件内部。 ===== 9.4 嵌套列表 ===== function CategoryList({ categories }) { return (
    {categories.map(category => (

    {category.name}

      {category.items.map(item => (
    • {item.name}
    • ))}
    ))}
    ; ); }
    ===== 9.5 列表过滤和排序 ===== **过滤列表**: function FilteredList({ items, filterText }) { const filtered = items.filter(item => item.name.toLowerCase().includes(filterText.toLowerCase()) ); return ( ; ); } **排序列表**: function SortedList({ items, sortBy }) { const sorted = [...items].sort((a, b) => { if (sortBy === 'name') { return a.name.localeCompare(b.name); } if (sortBy === 'date') { return new Date(b.date) - new Date(a.date); } return 0; }); return ( ; ); } ===== 9.6 虚拟列表 ===== 当列表项很多时,使用虚拟列表只渲染可视区域的内容。 **使用 react-window**: npm install react-window import { FixedSizeList as List } from 'react-window'; function VirtualList({ items }) { const Row = ({ index, style }) => (
    {items[index].name}
    ; ); return ( {Row} ; ); }
    **使用 react-virtualized**: npm install react-virtualized import { List } from 'react-virtualized'; function VirtualizedList({ items }) { const rowRenderer = ({ key, index, style }) => (
    {items[index].name}
    ; ); return ( ; ); }
    ===== 9.7 无限滚动 ===== import { useState, useEffect, useRef, useCallback } from 'react'; function InfiniteList() { const [items, setItems] = useState([]); const [page, setPage] = useState(1); const [loading, setLoading] = useState(false); const observer = useRef(); const lastItemRef = useCallback(node => { if (loading) return; if (observer.current) observer.current.disconnect(); observer.current = new IntersectionObserver(entries => { if (entries[0].isIntersecting) { setPage(prevPage => prevPage + 1); } }); if (node) observer.current.observe(node); }, [loading]); useEffect(() => { setLoading(true); fetchItems(page).then(newItems => { setItems(prev => [...prev, ...newItems]); setLoading(false); }); }, [page]); return (
    {items.map((item, index) => (
    {item.name}
    ; ))} {loading &&

    加载中...

    }
    ; ); }
    ===== 9.8 列表动画 ===== **使用 react-flip-toolkit**: npm install react-flip-toolkit import { Flipper, Flipped } from 'react-flip-toolkit'; function AnimatedList({ items }) { return ( i.id).join(',')}> ; ; ); } **使用 framer-motion**: npm install framer-motion import { motion, AnimatePresence } from 'framer-motion'; function AnimatedList({ items, onRemove }) { return ( {items.map(item => ( onRemove(item.id)} > {item.name} ; ))} ; ); } ===== 9.9 总结 ===== 本章介绍了列表渲染的各种技术: * 基础列表渲染 * Key 的重要性和最佳实践 * 列表过滤和排序 * 虚拟列表优化 * 无限滚动 * 列表动画 处理列表是 React 开发的常见场景,掌握这些技巧对于构建高性能应用非常重要。