工程实践 React

条件渲染与列表渲染

当条件为 false 时不渲染,为 true 时渲染内容:

发布于 2026/02/26 1 分钟

掌握动态渲染,让 UI 随数据变化

条件渲染

三元运算符

function Greeting({ isLoggedIn }) {
  return (
    <div>
      {isLoggedIn ? (
        <h1>欢迎回来!</h1>
      ) : (
        <h1>请登录</h1>
      )}
    </div>
  );
}

&& 运算符

当条件为 false 时不渲染,为 true 时渲染内容:

function Notification({ unreadCount }) {
  return (
    <div>
      <h1>消息</h1>
      {unreadCount > 0 && (
        <span>有 {unreadCount} 条未读消息</span>
      )}
    </div>
  );
}

注意:如果 unreadCount 为 0,会渲染 false,这是安全的。

switch 语句

function StatusBadge({ status }) {
  const getBadge = () => {
    switch (status) {
      case 'success':
        return <span className="badge success">成功</span>;
      case 'warning':
        return <span className="badge warning">警告</span>;
      case 'error':
        return <span className="badge error">错误</span>;
      default:
        return <span className="badge">未知</span>;
    }
  };

  return getBadge();
}

早期返回

function UserProfile({ user }) {
  // 加载状态
  if (!user) {
    return <div>加载中...</div>;
  }

  // 空状态
  if (user.posts.length === 0) {
    return <div>暂无动态</div>;
  }

  // 正常渲染
  return (
    <div>
      <h1>{user.name}</h1>
      <PostsList posts={user.posts} />
    </div>
  );
}

变量存储

function LoginButton({ isLoggedIn, onLogin, onLogout }) {
  let button;

  if (isLoggedIn) {
    button = <button onClick={onLogout}>登出</button>;
  } else {
    button = <button onClick={onLogin}>登录</button>;
  }

  return (
    <div>
      <h1>请登录</h1>
      {button}
    </div>
  );
}

列表渲染

基本 map 渲染

function ItemList() {
  const items = ['苹果', '香蕉', '橙子'];

  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
}

对象数组渲染

function UserList() {
  const users = [
    { id: 1, name: 'Alice', email: 'alice@example.com' },
    { id: 2, name: 'Bob', email: 'bob@example.com' },
    { id: 3, name: 'Charlie', email: 'charlie@example.com' }
  ];

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>
          <strong>{user.name}</strong>
          <span>{user.email}</span>
        </li>
      ))}
    </ul>
  );
}

渲染组件列表

function PostList({ posts }) {
  return (
    <div>
      {posts.map(post => (
        <PostCard key={post.id} post={post} />
      ))}
    </div>
  );
}

function PostCard({ post }) {
  return (
    <article>
      <h2>{post.title}</h2>
      <p>{post.excerpt}</p>
    </article>
  );
}

嵌套列表

function CategoryList({ categories }) {
  return (
    <div>
      {categories.map(category => (
        <div key={category.id} className="category">
          <h3>{category.name}</h3>
          <ul>
            {category.items.map(item => (
              <li key={item.id}>{item.name}</li>
            ))}
          </ul>
        </div>
      ))}
    </div>
  );
}

列表的 key

为什么需要 key?

Key 帮助 React 识别哪些元素发生了变化,提高渲染性能。

// ❌ 没有 key
items.map(item => <li>{item.name}</li>);

// ✅ 有 key
items.map(item => <li key={item.id}>{item.name}</li>);

使用稳定的 ID

// ❌ 不推荐:使用数组索引
items.map((item, index) => <li key={index}>{item.name}</li>);

// ✅ 推荐:使用唯一 ID
items.map(item => <li key={item.id}>{item.name}</li>);

// ✅ 备选:使用索引(但有条件)
items.map((item, index) => <li key={index}>{item.name}</li>);

key 的作用域

function App() {
  const [items, setItems] = useState([{ id: 1, name: 'A' }]);

  return (
    <div>
      {/* 这里的 key 影响这个范围内的元素 */}
      {items.map(item => (
        <div key={item.id}>
          <ChildComponent item={item} />
        </div>
      ))}
    </div>
  );
}

综合示例:待办清单

function TodoApp() {
  const [todos, setTodos] = useState([
    { id: 1, text: '学习 React', completed: false },
    { id: 2, text: '完成项目', completed: true },
    { id: 3, text: '写博客', completed: false }
  ]);

  const [inputValue, setInputValue] = useState('');

  const addTodo = () => {
    if (!inputValue.trim()) return;

    setTodos([
      ...todos,
      {
        id: Date.now(),
        text: inputValue,
        completed: false
      }
    ]);
    setInputValue('');
  };

  const toggleTodo = (id) => {
    setTodos(todos.map(todo =>
      todo.id === id
        ? { ...todo, completed: !todo.completed }
        : todo
    ));
  };

  const deleteTodo = (id) => {
    setTodos(todos.filter(todo => todo.id !== id));
  };

  const activeTodos = todos.filter(todo => !todo.completed);
  const completedTodos = todos.filter(todo => todo.completed);

  return (
    <div>
      <h1>待办清单</h1>

      {/* 添加输入框 */}
      <div className="input-group">
        <input
          value={inputValue}
          onChange={(e) => setInputValue(e.target.value)}
          onKeyDown={(e) => e.key === 'Enter' && addTodo()}
          placeholder="添加新任务..."
        />
        <button onClick={addTodo}>添加</button>
      </div>

      {/* 进行中的任务 */}
      <div className="section">
        <h2>进行中 ({activeTodos.length})</h2>
        {activeTodos.length === 0 ? (
          <p className="empty">暂无任务</p>
        ) : (
          <ul>
            {activeTodos.map(todo => (
              <li key={todo.id}>
                <input
                  type="checkbox"
                  checked={todo.completed}
                  onChange={() => toggleTodo(todo.id)}
                />
                <span>{todo.text}</span>
                <button onClick={() => deleteTodo(todo.id)}>删除</button>
              </li>
            ))}
          </ul>
        )}
      </div>

      {/* 已完成的任务 */}
      <div className="section">
        <h2>已完成 ({completedTodos.length})</h2>
        {completedTodos.map(todo => (
          <li key={todo.id}>
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleTodo(todo.id)}
            />
            <span className="completed">{todo.text}</span>
            <button onClick={() => deleteTodo(todo.id)}>删除</button>
          </li>
        ))}
      </div>
    </div>
  );
}

渲染的注意事项

1. 避免在 JSX 中直接使用对象

// ❌ 错误
<div>{ { name: 'test' } }</div>

// ✅ 正确
<div>{JSON.stringify({ name: 'test' })}</div>

2. 渲染数字

// ✅ 直接渲染数字
<p>数量: {count}</p>

// ✅ 渲染计算结果
<p>总价: {price * quantity}</p>

3. 渲染数组

const arr = [1, 2, 3];

// ✅ 渲染数组(自动调用 toString)
<p>{arr}</p>  // 输出: 1,2,3

// ✅ 使用 join
<p>{arr.join(', ')}</p>  // 输出: 1, 2, 3

总结

本章我们学习了:

  • 条件渲染的多种方式(三元运算符、&&、switch、早期返回)
  • 列表渲染的基本方法
  • key 的重要性
  • 综合示例:待办清单

下一章我们将学习 React Hooks 的核心——useState。