提升 React:精通列表、键和组件模式!(React 第4天)

发布: (2026年1月12日 GMT+8 12:30)
7 min read
原文: Dev.to

抱歉,我需要您提供要翻译的具体文本内容(文章正文),才能为您完成翻译。请把需要翻译的部分粘贴在这里,我会按照要求保留源链接、格式和代码块进行翻译。

React 中的列表

工作原理
使用像 map() 这样的数组方法将数据转换为 JSX。每个项目都会变成一个组件或元素。

实用示例:基础待办列表

import { useState } from 'react';

function TodoList() {
  const [todos, setTodos] = useState(['Buy milk', 'Walk dog', 'Code React']);

  return (
    

      {todos.map((todo, index) => (
        - {todo}
 {/* Keys coming up next! */}
      ))}
    

  );
}

这会渲染一个无序列表。你可以通过表单等方式添加状态更新,以实现动态效果。

UI 场景

在购物车应用中:

{cart.map(item => (
  
))}

用户可以添加/移除商品,界面会无缝更新。

常见错误

忘记处理空列表可能导致界面空白。添加条件判断:

{todos.length ? (
  todos.map((todo, i) => - {todo}
)
) : (
  
No todos!

)}

最佳实践

保持映射逻辑简洁;将复杂的项提取为子组件,以提升可读性。


键是通过 key 属性分配给列表项的唯一字符串(或数字)。它们 不会 传递给组件;而是被 React 在内部使用。

为什么键在内部很重要

在调和(React 的 diff 算法)过程中,键帮助识别哪些项目被添加、删除或更改。没有稳定的键,React 会退回使用基于索引的匹配,这可能导致更新错误。

性能影响

使用合适的键可以最小化 DOM 操作——React 能复用元素而不是重新创建它们。错误的键会导致不必要的重新渲染、界面闪烁以及组件状态丢失(例如输入框焦点)。

实际示例:带有稳定键的动态列表

function UserList({ users }) {
  return (
    

      {users.map(user => (
        - {user.name}
 {/* Use stable ID like a database key */}
      ))}
    

  );
}

如果 users 的顺序被重新排列,键能够确保平滑的过渡。

常见错误

  • 使用索引作为键 – 仅在静态列表中可接受;在可排序/可过滤的列表中会导致灾难。
  • 键重复 – React 会给出警告;键必须在同级兄弟节点中唯一。
  • 没有键 – 控制台警告并且渲染效率低下。

UI 场景

在聊天应用中:

{messages.map(msg => (
  
))}

如果没有合适的键,滚动或新消息可能会导致焦点重置或动画中断。

最佳实践

使用稳定、唯一的 ID(例如来自 API 的数据)。避免在每次渲染时都会变化的随机键。

Source:

组件模式

可复用的组件受益于清晰的模式,这些模式促进模块化和关注点分离。

常见模式

  • 表现层 vs. 容器层(Smart vs. Dumb) – 表现层组件负责 UI;容器层组件管理逻辑(状态、数据获取),并向下传递数据。
  • 复合组件 – 将共享隐式状态的相关组件组合在一起(例如 )。
  • 渲染属性 / 高阶组件(Render Props / HOCs) – 高级复用技术;hooks 通常提供更简洁的替代方案。

实践示例:容器‑表现层拆分

// Presentational: Pure UI
function UserDisplay({ user }) {
  return Name: {user.name}, Age: {user.age};
}

// Container: Logic
import { useState, useEffect } from 'react';

function UserContainer() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // Simulate fetch
    setUser({ name: 'Alex', age: 28 });
  }, []);

  return user ?  : 
Loading...
;
}

UI 场景

一个仪表盘可能有一个 ChartContainer 用于获取数据,并将数据传递给 ChartDisplay 组件,从而使相同的展示逻辑能够在不同查询的页面之间复用。

最佳实践

从简单开始;随着组件的增长再重构为相应的模式。TypeScript 可以帮助强制可复用组件的属性契约。

关注点分离

将职责划分——UI 与逻辑、状态 与 渲染——可以让测试、调试和协作更容易。

如何应用

  • 提取逻辑 到自定义 Hook 或工具模块。
  • 保持组件专注:一个组件负责获取数据,另一个负责渲染。

实际示例

上面的 UserContainer 将数据获取与展示分离。相同的原则适用于列表渲染:一个 Hook 获取用户数据,而 UserList 只负责将其映射为 JSX。

常见错误

单块组件同时处理获取、状态和 UI,会导致难以复用或测试。应及早拆分。

UI 场景

在新闻推送中:

  • FeedContainer 负责 API 调用、分页和错误处理。
  • FeedItem 仅渲染文章。
    你可以在不触及数据获取逻辑的情况下更换展示组件。

最佳实践

采用“每个文件只关注一个职责”的方法:

src/
 ├─ components/
 │   ├─ containers/
 │   └─ presentational/
 └─ hooks/

这种结构强化了明确的边界并促进了可复用性。

Back to Blog

相关文章

阅读更多 »