从 Vue3 到 React · 快速上手系列第 4 篇:条件渲染与列表渲染

面向 Vue3 开发者的 React 快速上手系列

v-ifv-for 是 Vue 模板里用得最多的两个指令。React 没有指令------因为 JSX 就是 JS,条件用三元/逻辑运算符,循环用 .map() 。这一篇把这两个高频场景讲透,包括 Vue 开发者最容易忽略的 key


一、条件渲染

1. v-if&&(有就显示,没有就不显示)

vue 复制代码
<!-- Vue3 -->
<p v-if="isLoggedIn">欢迎回来</p>
jsx 复制代码
// React
{isLoggedIn && <p>欢迎回来</p>}

原理:&& 左边为真时返回右边的 JSX,为假时返回 false(React 会忽略 falsenullundefined,什么都不渲染)。

⚠️ 一个大坑&& 左边是数字 0 时会把 0 渲染出来!

jsx 复制代码
{list.length && <List />}   // ❌ list 为空时页面会显示 "0"
{list.length > 0 && <List />} // ✅ 用明确的布尔判断

2. v-if / v-else → 三元表达式

vue 复制代码
<!-- Vue3 -->
<p v-if="isLoggedIn">欢迎回来</p>
<p v-else>请登录</p>
jsx 复制代码
// React
{isLoggedIn ? <p>欢迎回来</p> : <p>请登录</p>}

3. v-if / v-else-if / v-else → 提前 return 或变量

多分支时,三元嵌套会很丑。React 常用两种更清爽的写法:

写法 A:提前 return(适合整个组件的分支)

jsx 复制代码
function UserPanel({ status }) {
  if (status === 'loading') return <Spinner />
  if (status === 'error')   return <ErrorTip />
  return <Content />
}

写法 B:先算好变量再渲染

jsx 复制代码
function Badge({ level }) {
  let label
  if (level === 1) label = <span className="gold">金牌</span>
  else if (level === 2) label = <span className="silver">银牌</span>
  else label = <span>普通</span>

  return <div>{label}</div>
}

4. v-show 的等价物

Vue 的 v-show 是切换 display,元素始终在 DOM 里。React 没有内置等价物,自己控制 style 即可:

jsx 复制代码
<div style={{ display: visible ? 'block' : 'none' }}>内容</div>

区别提醒:{cond && <X/>} 类似 v-if(真正增删 DOM);上面的 style 写法类似 v-show(只切换显示)。


二、列表渲染

1. v-for.map()

vue 复制代码
<!-- Vue3 -->
<ul>
  <li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
jsx 复制代码
// React
<ul>
  {items.map(item => (
    <li key={item.id}>{item.name}</li>
  ))}
</ul>

核心:用数组的 .map() 把"数据数组"变成"JSX 数组",React 会把数组里的元素依次渲染。

2. key 同样重要(而且规则一样)

和 Vue 一样,React 要求列表每一项有唯一的 key,用于高效 diff。规则也完全一致:

jsx 复制代码
// ✅ 用稳定的唯一 id
{items.map(item => <li key={item.id}>{item.name}</li>)}

// ❌ 用数组下标做 key(列表会增删/排序时会出 bug),和 Vue 的告诫一样
{items.map((item, index) => <li key={index}>{item.name}</li>)}

key 要写在 .map() 返回的最外层元素 上,这点和 Vue 把 :key 放在 v-for 元素上一致。

3. 带索引、带过滤

jsx 复制代码
// 带索引
{items.map((item, index) => (
  <li key={item.id}>{index + 1}. {item.name}</li>
))}

// 过滤后渲染(对标 v-for 配合 v-if,但更清晰)
{items
  .filter(item => item.active)
  .map(item => <li key={item.id}>{item.name}</li>)}

💡 Vue 官方不推荐 v-forv-if 同时用在一个元素上;React 里天然用 filter().map() 链式解决,反而更自然。

4. 渲染对象/Map

Vue 的 v-for 能直接遍历对象。React 里先把对象转成数组:

jsx 复制代码
{Object.entries(user).map(([key, value]) => (
  <li key={key}>{key}: {value}</li>
))}

三、空状态处理

列表为空时的"暂无数据",React 用条件渲染组合即可:

jsx 复制代码
function TodoList({ todos }) {
  return (
    <div>
      {todos.length === 0 ? (
        <p className="empty">暂无待办</p>
      ) : (
        <ul>
          {todos.map(t => <li key={t.id}>{t.text}</li>)}
        </ul>
      )}
    </div>
  )
}

四、综合示例:一个完整的可交互列表

把条件渲染、列表渲染、状态、事件串起来看一个真实例子:

jsx 复制代码
import { useState } from 'react'

function ShoppingList() {
  const [items, setItems] = useState([
    { id: 1, name: '苹果', done: false },
    { id: 2, name: '牛奶', done: true },
  ])

  const toggle = (id) => {
    setItems(items.map(item =>
      item.id === id ? { ...item, done: !item.done } : item   // 不可变更新
    ))
  }

  const remaining = items.filter(i => !i.done).length

  return (
    <div>
      {remaining > 0
        ? <p>还有 {remaining} 项未完成</p>
        : <p>全部完成 🎉</p>}

      {items.length === 0 ? (
        <p>清单是空的</p>
      ) : (
        <ul>
          {items.map(item => (
            <li
              key={item.id}
              onClick={() => toggle(item.id)}
              style={{ textDecoration: item.done ? 'line-through' : 'none' }}
            >
              {item.name}
            </li>
          ))}
        </ul>
      )}
    </div>
  )
}

这段代码涵盖了:&& 之外的三元条件、.map() 列表、keyfilter 派生、不可变更新、事件处理------全是前几篇的知识点。


五、对照速查

场景 Vue3 React
单条件显示 v-if {cond && <X/>}
二选一 v-if / v-else {cond ? <A/> : <B/>}
多分支 v-else-if 提前 return 或变量
切换显示(不删 DOM) v-show style={{display: ...}}
列表渲染 v-for + :key .map() + key
遍历对象 v-for 遍历对象 Object.entries().map()
过滤+渲染 v-for + 计算属性 .filter().map()

小结

  • 条件:&&(单条件,注意数字 0 的坑)、三元(二选一)、提前 return(多分支)。
  • v-showstyle={{display}} 模拟。
  • 列表:.map() 生成 JSX 数组,别忘了 key,别用数组下标当 key。
  • v-for + v-if.filter().map() 链式替代,更清晰。
  • 一切都是纯 JS,没有"指令"要记。

下一篇讲事件处理与表单 ------重点是 React 没有 v-model,你需要理解"受控组件"。

相关推荐
颜进强1 小时前
从零搭建私人 RAG 实战:用 Markdown 沉淀技术决策与业务决策
前端·后端·ai编程
咩咩啃树皮1 小时前
第46篇:Vue3 Router工程化进阶——懒加载+嵌套路由+全局守卫+权限控制
javascript·vue.js·ecmascript
为你学会写情书1 小时前
手写 Mini React 核心原理解析
react.js
触底反弹1 小时前
💡 React 父子组件通信:一个进度条教会我的 5 件事
前端·react.js·面试
咩咩啃树皮1 小时前
第44篇:Vue3侦听器完全精讲——watch与watchEffect区别、深度监听、异步业务落地
前端·javascript·vue.js
Python私教1 小时前
前端转 AI 全栈:别只做聊天框,SSE 与审批流才是分水岭
前端·人工智能
晓得迷路了2 小时前
栗子前端技术周刊第 139 期 - Nuxt 4.5、Vue 3.6 RC、Angular 发布节奏...
前端·javascript·vue.js
鱼樱前端2 小时前
AI 会不会取代前端?我看了 2026 年 7 月整个市场,给你一个不吓人的答案
前端·程序员·ai编程
এ慕ོ冬℘゜2 小时前
原生 select 下拉框搜索失效踩坑:文本搜索与 ID 匹配不对应问题排查
前端·javascript·html