面向 Vue3 开发者的 React 快速上手系列
v-if 和 v-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 会忽略 false、null、undefined,什么都不渲染)。
⚠️ 一个大坑 :
&&左边是数字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-for和v-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() 列表、key、filter 派生、不可变更新、事件处理------全是前几篇的知识点。
五、对照速查
| 场景 | 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-show用style={{display}}模拟。- 列表:
.map()生成 JSX 数组,别忘了key,别用数组下标当 key。 v-for + v-if用.filter().map()链式替代,更清晰。- 一切都是纯 JS,没有"指令"要记。
下一篇讲事件处理与表单 ------重点是 React 没有 v-model,你需要理解"受控组件"。