一、本课目标
学完这一课,你要建立六个认知:
本课核心线索:
视图 = 函数(状态)
↓
状态有多个分支 → 函数根据分支返回不同 UI 描述
↓
条件渲染:if/else、三元、逻辑与
↓
多条件组合:按优先级选择
↓
条件渲染与 key:同一位置的不同分支需要区分
↓
性能考量:避免不必要的重渲染
↓
实战:清晰、可维护、无 bug
二、条件渲染的本质
2.1 一句话说透
条件渲染就是"根据状态选择不同的 UI 描述":
视图 = 函数(状态)
↓ 状态有多个分支
↓ 函数根据状态分支返回不同 UI 描述
关键理解: 条件渲染不是"手动显示/隐藏控件",而是"函数根据状态返回不同的 UI 描述"。状态变化,函数重新执行,返回新的 UI 描述。
2.2 条件渲染 vs 命令式显示/隐藏
命令式:手动显示/隐藏。
// JavaScript
// 命令式:手动控制可见性
if (isLoading) {
spinner.style.display = 'block'
content.style.display = 'none'
} else {
spinner.style.display = 'none'
content.style.display = 'block'
}
声明式:根据状态返回不同描述。
// TSX (React Native)
// 声明式:根据状态返回不同 UI 描述
function View({ isLoading }) {
if (isLoading) return <Spinner />
return <Content />
}
关键区别:
维度 命令式 声明式
做法 手动显示/隐藏控件 根据状态返回不同描述
状态与 UI 手动同步 自动映射
代码 多条命令 一个分支
2.3 条件渲染的三层含义
第一层:条件是状态的一部分。
状态:isLoading
→ true → 返回 <Spinner />
→ false → 返回 <Content />
第二层:分支是函数的自然表达。
函数(状态) = if (isLoading) <Spinner /> else <Content />
第三层:状态变化触发分支重算。
isLoading: true → false
→ 函数重新执行
→ 返回 <Content />
→ 框架对比新旧描述,如果有差异就通知底层更新
2.4 各框架条件渲染对照
框架 条件渲染方式
React Native if/else、三元、&&
SwiftUI if/else、switch、@ViewBuilder
ArkUI if/else、ForEach + 条件
Compose if/else、when
Flutter if/else、三元、??
关键结论: 五种框架的条件渲染本质相同——根据状态选择不同的 UI 描述。差异只在语法。
三、条件渲染的基本写法
3.1 if/else 写法
适用场景: 两个或多个互斥分支。
React Native:
// TSX (React Native)
function View({ isLoading, error, data }) {
// 多分支:if/else
if (isLoading) return <Spinner />
if (error) return <Error message={error} />
return <Content data={data} />
}
SwiftUI:
// Swift (SwiftUI)
struct ContentView: View {
let isLoading: Bool
let error: String?
let data: [Item]
var body: some View {
// 多分支:if/else if/else
if isLoading {
Spinner()
} else if let error = error {
ErrorView(message: error)
} else {
ListView(data: data)
}
}
}
ArkUI:
// ArkTS (ArkUI)
@Component
struct ContentView {
@Prop isLoading: boolean
@Prop error: string
@Prop data: Item[]
build() {
// 多分支:if/else if/else
if (this.isLoading) {
Spinner()
} else if (this.error) {
ErrorView({ message: this.error })
} else {
ListView({ data: this.data })
}
}
}
Compose:
// Kotlin (Jetpack Compose)
@Composable
fun ContentView(
isLoading: Boolean,
error: String?,
data: List<Item>
) {
// 多分支:if/else if/else
if (isLoading) {
Spinner()
} else if (error != null) {
ErrorView(message = error)
} else {
ListView(data = data)
}
}
Flutter:
// Dart (Flutter)
Widget build(BuildContext context) {
// 多分支:if/else if/else
if (isLoading) {
return Spinner();
} else if (error != null) {
return ErrorView(message: error!);
} else {
return ListView(data: data);
}
}
3.2 三元表达式写法
适用场景: 两个分支,且适合内联。
React Native:
// TSX (React Native)
function Toggle({ isOn }) {
// 三元:两个分支
return (
<Text>{isOn ? '开' : '关'}</Text>
)
}
SwiftUI:
// Swift (SwiftUI)
struct ToggleView: View {
let isOn: Bool
var body: some View {
// 三元:两个分支
Text(isOn ? "开" : "关")
}
}
ArkUI:
// ArkTS (ArkUI)
@Component
struct ToggleView {
@Prop isOn: boolean
build() {
// 三元:两个分支
Text(this.isOn ? '开' : '关')
}
}
Compose:
// Kotlin (Jetpack Compose)
@Composable
fun ToggleView(isOn: Boolean) {
// 三元:两个分支(Kotlin 用 if 表达式)
Text(if (isOn) "开" else "关")
}
Flutter:
// Dart (Flutter)
Widget build(BuildContext context) {
// 三元:两个分支
return Text(isOn ? '开' : '关');
}
3.3 逻辑与写法
适用场景: 条件为真时渲染,为假时不渲染。
React Native:
// TSX (React Native)
function List({ items }) {
return (
<View>
{/* 逻辑与:items 为空时显示 */}
{items.length === 0 && <Text>暂无数据</Text>}
{/* 逻辑与:有数据时渲染列表 */}
{items.length > 0 && (
<View>
{items.map(item => <Item key={item.id} {…item} />)}
</View>
)}
</View>
)
}
SwiftUI:
// Swift (SwiftUI)
struct ListView: View {
let items: [Item]
var body: some View {
VStack {
// SwiftUI 没有逻辑与,用 if
if items.isEmpty {
Text("暂无数据")
}
if !items.isEmpty {
ForEach(items) { item in
ItemView(item: item)
}
}
}
}
}
ArkUI:
// ArkTS (ArkUI)
@Component
struct ListView {
@Prop items: Item[]
build() {
Column() {
// ArkUI 用 if
if (this.items.length === 0) {
Text('暂无数据')
}
if (this.items.length > 0) {
ForEach(this.items, (item: Item) => {
ItemView({ item: item })
}, (item: Item) => item.id.toString())
}
}
}
}
Compose:
// Kotlin (Jetpack Compose)
@Composable
fun ListView(items: List<Item>) {
Column {
// Compose 用 if
if (items.isEmpty()) {
Text("暂无数据")
}
if (items.isNotEmpty()) {
items.forEach { item ->
key(item.id) {
ItemView(item)
}
}
}
}
}
Flutter:
// Dart (Flutter)
Widget build(BuildContext context) {
return Column(
children: [
// Dart 用 collection if
if (items.isEmpty) Text('暂无数据'),
if (items.isNotEmpty)
...items.map((item) => ItemView(
key: ValueKey(item.id),
item: item,
)),
],
);
}
3.4 三种写法的选择
写法 适用场景 优点 缺点
if/else 多分支、互斥 清晰、易读 不能内联
三元 两分支、内联 简洁 嵌套可读性差
逻辑与 条件为真时渲染 简洁 假值陷阱
选择原则:
1. 多分支 → if/else
2. 两分支且适合内联 → 三元
3. 条件为真时渲染,为假时不渲染 → 逻辑与
4. 嵌套过深 → 提取为独立组件或函数
3.5 各框架条件渲染对照
框架 if/else 三元 逻辑与
React Native if/else a ? b : c a && b
SwiftUI if/else a ? b : c 不支持,用 if
ArkUI if/else a ? b : c 不支持,用 if
Compose if/else if (a) b else c 不支持,用 if
Flutter if/else a ? b : c collection if
四、多条件组合
4.1 多状态的优先级
当多个状态同时存在时,渲染函数按优先级选择 UI 描述。
// TSX (React Native)
function View({ isLoading, error, data }) {
// 优先级:加载中 > 错误 > 正常
if (isLoading) return <Spinner />
if (error) return <Error message={error} />
return <Content data={data} />
}
优先级设计原则:
1. 加载态优先于错误态
→ 正在加载时,不显示错误
2. 错误态优先于正常态
→ 有错误时,不显示内容
3. 空态优先于正常态
→ 数据为空时,显示"暂无数据"
4. 权限态优先于内容态
→ 无权限时,不显示内容
4.2 优先级的具体设计
示例:一个完整的页面状态设计。
// TSX (React Native)
function Page({ isLoading, error, data, hasPermission, isEmpty }) {
// 1. 权限检查(最高优先级)
if (!hasPermission) return <NoPermission />
// 2. 加载中
if (isLoading) return <Spinner />
// 3. 错误
if (error) return <Error message={error} />
// 4. 空态
if (isEmpty) return <Empty />
// 5. 正常内容
return <Content data={data} />
}
优先级流程图:
┌─────────────────┐
│ hasPermission? │
└────────┬────────┘
│ 否
↓
<NoPermission />
│ 是
↓
┌─────────────────┐
│ isLoading? │
└────────┬────────┘
│ 是
↓
<Spinner />
│ 否
↓
┌─────────────────┐
│ error? │
└────────┬────────┘
│ 是
↓
<Error />
│ 否
↓
┌─────────────────┐
│ isEmpty? │
└────────┬────────┘
│ 是
↓
<Empty />
│ 否
↓
<Content />
4.3 多状态组合的常见错误
错误一:状态之间互相矛盾。
// TSX (React Native)
// 错误:isLoading 和 error 同时为 true 时,显示什么?
function View({ isLoading, error, data }) {
return (
<View>
{isLoading && <Spinner />}
{error && <Error message={error} />}
{!isLoading && !error && <Content data={data} />}
</View>
)
}
问题: 如果 isLoading 和 error 同时为 true,会同时显示 Spinner 和 Error。
修正: 用 if/else 表达优先级。
// TSX (React Native)
function View({ isLoading, error, data }) {
if (isLoading) return <Spinner />
if (error) return <Error message={error} />
return <Content data={data} />
}
错误二:条件判断过于复杂。
// TSX (React Native)
// 错误:条件判断过于复杂
function View({ user, post, comment }) {
return (
<View>
{user && user.isLoggedIn && post && post.isPublished && !comment && (
<Content />
)}
</View>
)
}
修正: 提取为派生数据。
// TSX (React Native)
function View({ user, post, comment }) {
// 派生数据:把复杂条件提取出来
const shouldShowContent =
user?.isLoggedIn &&
post?.isPublished &&
!comment
return (
<View>
{shouldShowContent && <Content />}
</View>
)
}
错误三:嵌套三元过深。
// TSX (React Native)
// 错误:嵌套三元过深
function View({ status }) {
return (
<Text>
{status === 'loading' ? '加载中' :
status === 'error' ? '错误' :
status === 'empty' ? '暂无数据' :
'正常'}
</Text>
)
}
修正: 用 if/else 或 switch。
// TSX (React Native)
function View({ status }) {
if (status === 'loading') return <Text>加载中</Text>
if (status === 'error') return <Text>错误</Text>
if (status === 'empty') return <Text>暂无数据</Text>
return <Text>正常</Text>
}
4.4 各框架多条件组合对照
React Native:
// TSX (React Native)
if (isLoading) return <Spinner />
if (error) return <Error />
return <Content />
SwiftUI:
// Swift (SwiftUI)
if isLoading {
Spinner()
} else if let error = error {
ErrorView(message: error)
} else {
Content()
}
ArkUI:
// ArkTS (ArkUI)
if (this.isLoading) {
Spinner()
} else if (this.error) {
ErrorView({ message: this.error })
} else {
Content()
}
Compose:
// Kotlin (Jetpack Compose)
when {
isLoading -> Spinner()
error != null -> ErrorView(message = error)
else -> Content()
}
Flutter:
// Dart (Flutter)
if (isLoading) {
return Spinner();
} else if (error != null) {
return ErrorView(message: error!);
} else {
return Content();
}
五、条件渲染与 key
5.1 同一位置的不同分支需要 key
问题: 同一位置的不同分支,框架可能认为是同一个元素,导致状态错乱。
// TSX (React Native)
// 问题:同一位置切换分支,状态可能错乱
function View({ isOn }) {
return (
<View>
{isOn ? <OnComponent /> : <OffComponent />}
</View>
)
}
问题分析:
isOn: true → false
框架对比:
旧:位置 0 是 <OnComponent />
新:位置 0 是 <OffComponent />
→ 框架认为:位置 0 的元素类型变了 → 销毁旧的,创建新的
→ 状态正确
但如果两个分支都是同类型元素:
旧:位置 0 是 <Text>开</Text>
新:位置 0 是 <Text>关</Text>
→ 框架认为:位置 0 的 Text 内容变了 → 复用,更新内容
→ 如果 Text 有内部状态,状态可能错乱
修正: 给不同分支加 key。
// TSX (React Native)
function View({ isOn }) {
return (
<View>
{isOn
? <OnComponent key="on" />
: <OffComponent key="off" />
}
</View>
)
}
5.2 key 在条件渲染中的应用
示例:切换登录/注册表单。
// TSX (React Native)
function AuthForm({ mode }) {
return (
<View>
{mode === 'login' ? (
<LoginForm key="login" />
) : (
<RegisterForm key="register" />
)}
</View>
)
}
加 key 的效果: 切换模式时,框架销毁旧表单,创建新表单。表单的输入框状态被清空,符合用户预期。
不加 key 的效果: 如果 LoginForm 和 RegisterForm 结构相似,框架可能复用元素,输入框状态被保留,不符合用户预期。
5.3 各框架条件渲染的 key 对照
React Native:
// TSX (React Native)
{mode === 'login' ? <LoginForm key="login" /> : <RegisterForm key="register" />}
SwiftUI:
// Swift (SwiftUI)
// SwiftUI 自动处理 if/else 分支的身份
if mode == .login {
LoginForm()
} else {
RegisterForm()
}
// 如需强制重建,用 .id()
if mode == .login {
LoginForm().id("login")
} else {
RegisterForm().id("register")
}
ArkUI:
// ArkTS (ArkUI)
// ArkUI 的 if/else 自动处理分支
if (this.mode === 'login') {
LoginForm()
} else {
RegisterForm()
}
Compose:
// Kotlin (Jetpack Compose)
// Compose 的 if/else 自动处理分支
if (mode == "login") {
LoginForm()
} else {
RegisterForm()
}
// 如需强制重建,用 key()
key(mode) {
if (mode == "login") {
LoginForm()
} else {
RegisterForm()
}
}
Flutter:
// Dart (Flutter)
// Flutter 需要手动指定 key
mode == 'login'
? LoginForm(key: ValueKey('login'))
: RegisterForm(key: ValueKey('register'))
5.4 key 与条件渲染的配合
原则:
1. 如果两个分支是不同类型的组件 → 框架自动区分,不需要 key
2. 如果两个分支是相同类型的组件 → 需要 key 区分
3. 如果希望切换时状态清空 → 加 key
4. 如果希望切换时状态保留 → 不加 key
示例:
// TSX (React Native)
// 场景:同一位置切换两个 Text 组件
function View({ isOn }) {
return (
<View>
{isOn
? <Text key="on">开</Text>
: <Text key="off">关</Text>
}
</View>
)
}
分析: 两个分支都是 Text 组件。如果不加 key,框架认为位置 0 的 Text 内容变了,复用元素。如果 Text 有内部状态(比如动画),状态可能错乱。加 key 后,框架知道这是两个不同的元素,正确销毁和创建。
六、条件渲染的性能考量
6.1 避免不必要的重渲染
问题: 条件渲染的组件在状态变化时重新渲染。
// TSX (React Native)
// 问题:count 变化,ComplexView 重新渲染
function View({ count }) {
return (
<View>
<Text>Count: {count}</Text>
{count > 0 && <ComplexView />}
</View>
)
}
分析: count 从 1 变到 2,count > 0 仍然为 true,但 ComplexView 重新渲染了。
修正: 使用 React.memo 或 EquatableView。
// TSX (React Native)
const ComplexView = React.memo(function ComplexView() {
// 复杂布局
return <View>…</View>
})
function View({ count }) {
return (
<View>
<Text>Count: {count}</Text>
{count > 0 && <ComplexView />}
</View>
)
}
6.2 条件判断的开销
问题: 条件判断过于复杂,每次渲染都重新计算。
// TSX (React Native)
// 问题:复杂条件每次渲染都重新计算
function View({ items, filter, sort }) {
return (
<View>
{items
.filter(item => item.category === filter)
.sort((a, b) => a[sort] – b[sort])
.length > 0 && (
<Content />
)}
</View>
)
}
修正: 用 useMemo 缓存计算结果。
// TSX (React Native)
function View({ items, filter, sort }) {
const filteredItems = useMemo(() => {
return items
.filter(item => item.category === filter)
.sort((a, b) => a[sort] – b[sort])
}, [items, filter, sort])
return (
<View>
{filteredItems.length > 0 && <Content />}
</View>
)
}
6.3 条件渲染的粒度
问题: 条件渲染粒度过粗,导致不必要的重渲染。
// TSX (React Native)
// 问题:整个 View 重新渲染
function View({ isLoading, data }) {
if (isLoading) return <Spinner />
return (
<View>
<Header />
<Content data={data} />
<Footer />
</View>
)
}
修正: 把条件渲染粒度细化到需要的部分。
// TSX (React Native)
function View({ isLoading, data }) {
return (
<View>
<Header />
{isLoading ? <Spinner /> : <Content data={data} />}
<Footer />
</View>
)
}
分析: Header 和 Footer 不依赖 isLoading,条件渲染粒度细化后,isLoading 变化只影响 Content 部分。
6.4 条件渲染的性能检查清单
条件渲染性能检查清单:
1. 条件渲染的组件是否使用了 memo/equatable?
→ 避免不必要的重渲染
2. 条件判断是否过于复杂?
→ 用 useMemo 缓存计算结果
3. 条件渲染的粒度是否过粗?
→ 细化到需要的部分
4. 条件渲染的分支是否有内部状态?
→ 有 → 用 key 区分
→ 没有 → 不需要 key
5. 条件渲染的分支是否频繁切换?
→ 频繁切换 → 用动画过渡
→ 不频繁 → 直接切换
6.5 各框架条件渲染性能对照
框架 性能优化 API 关键差异
React Native React.memo、useMemo 需要手动优化
SwiftUI EquatableView、@ViewBuilder 声明式,自动优化
ArkUI @Reusable 需要手动优化
Compose remember、derivedStateOf 自动跳过不变的重组
Flutter const、RepaintBoundary 需要手动优化
七、常见误区
7.1 逻辑与的假值陷阱
React Native:
// TSX (React Native)
// 错误:count 为 0 时,会渲染 0
{count && <Text>Count: {count}</Text>}
// 正确:用明确的条件
{count > 0 && <Text>Count: {count}</Text>}
问题: 在 JavaScript 中,0 && 返回 0,React 会渲染 0。
修正: 用明确的条件判断。
// TSX (React Native)
// 正确:用三元或明确的条件
{count > 0 ? <Text>Count: {count}</Text> : null}
7.2 条件渲染的 key 遗漏
// TSX (React Native)
// 错误:切换分支时状态错乱
{isOn ? <Text>开</Text> : <Text>关</Text>}
// 正确:加 key 区分
{isOn ? <Text key="on">开</Text> : <Text key="off">关</Text>}
7.3 嵌套三元过深
// TSX (React Native)
// 错误:嵌套三元过深
{status === 'loading' ? <Spinner /> :
status === 'error' ? <Error /> :
status === 'empty' ? <Empty /> :
<Content />}
// 正确:用 if/else 或提取函数
function renderContent() {
if (status === 'loading') return <Spinner />
if (status === 'error') return <Error />
if (status === 'empty') return <Empty />
return <Content />
}
7.4 条件判断放在错误的位置
// TSX (React Native)
// 错误:条件判断放在子组件内部
function Parent({ isLoading }) {
return <Child isLoading={isLoading} />
}
function Child({ isLoading }) {
if (isLoading) return <Spinner />
return <Content />
}
// 正确:条件判断放在父组件
function Parent({ isLoading }) {
if (isLoading) return <Spinner />
return <Child />
}
function Child() {
return <Content />
}
分析: 如果 Child 有其他 props 变化,即使 isLoading 没变,Child 也会重新渲染。把条件判断放在父组件,isLoading 为 true 时不渲染 Child,避免不必要的重渲染。
7.5 条件渲染与列表 key 混淆
// TSX (React Native)
// 错误:把条件渲染的 key 和列表的 key 混淆
{items.map(item => (
item.isVisible && <Item key={item.id} {…item} />
))}
// 问题:item.isVisible 为 false 时,返回 false,React 会渲染 false
// 正确:用 filter
{items.filter(item => item.isVisible).map(item => (
<Item key={item.id} {…item} />
))}
7.6 条件渲染的状态不同步
// TSX (React Native)
// 错误:条件渲染的状态不同步
const [isOn, setIsOn] = useState(false)
const [label, setLabel] = useState('关')
const toggle = () => {
setIsOn(!isOn)
setLabel(isOn ? '关' : '开') // 容易漏
}
// 正确:单一数据源
const [isOn, setIsOn] = useState(false)
const label = isOn ? '开' : '关' // 派生数据
7.7 条件渲染的默认分支遗漏
// TSX (React Native)
// 错误:没有默认分支,status 异常时什么都不显示
function View({ status }) {
if (status === 'loading') return <Spinner />
if (status === 'error') return <Error />
if (status === 'success') return <Content />
// status 为其他值时,返回 undefined
}
// 正确:加默认分支
function View({ status }) {
if (status === 'loading') return <Spinner />
if (status === 'error') return <Error />
if (status === 'success') return <Content />
return <Empty /> // 默认分支
}
八、习题(15 道)
题目 1(选择题)
条件渲染的本质是什么?
A. 手动显示/隐藏控件
B. 根据状态选择不同的 UI 描述
C. 循环创建视图
D. 命令式更新界面
参考答案:B
解读: 条件渲染是"根据状态选择不同的 UI 描述",是 视图 = 函数(状态) 在分支逻辑上的体现。A、D 是命令式思维,C 是列表渲染。
题目 2(判断题)
条件渲染中,同一位置的不同分支必须加 key 区分。
参考答案:错误
解读: 如果两个分支是不同类型的组件,框架自动区分,不需要 key。只有两个分支是相同类型组件,且希望切换时状态清空,才需要加 key。
题目 3(填空题)
条件渲染的三种基本写法是:、、______。
参考答案:if/else;三元表达式;逻辑与
解读: if/else 适合多分支互斥场景;三元适合两分支且适合内联;逻辑与适合条件为真时渲染,为假时不渲染。
题目 4(简答题)
多条件组合时,如何设计优先级?
参考答案: 多条件组合时,渲染函数按优先级选择 UI 描述。优先级设计原则:
用 if/else 表达优先级,从上到下依次判断,第一个为 true 的分支被渲染。
题目 5(代码分析题)
下面代码有什么问题?如何修正?
// TSX (React Native)
function View({ isLoading, error, data }) {
return (
<View>
{isLoading && <Spinner />}
{error && <Error message={error} />}
{!isLoading && !error && <Content data={data} />}
</View>
)
}
参考答案: 如果 isLoading 和 error 同时为 true,会同时显示 Spinner 和 Error,不符合预期。
修正: 用 if/else 表达优先级。
// TSX (React Native)
function View({ isLoading, error, data }) {
if (isLoading) return <Spinner />
if (error) return <Error message={error} />
return <Content data={data} />
}
题目 6(代码改错题)
下面代码有什么问题?如何修正?
// TSX (React Native)
{count && <Text>Count: {count}</Text>}
参考答案: 当 count 为 0 时,0 && 返回 0,React 会渲染 0。
修正: 用明确的条件判断。
// TSX (React Native)
{count > 0 && <Text>Count: {count}</Text>}
题目 7(跨框架对比题)
写出 React Native、SwiftUI、Compose 中条件渲染的核心写法。
参考答案:
React Native:
// TSX (React Native)
if (isLoading) return <Spinner />
if (error) return <Error />
return <Content />
SwiftUI:
// Swift (SwiftUI)
if isLoading {
Spinner()
} else if let error = error {
ErrorView(message: error)
} else {
Content()
}
Compose:
// Kotlin (Jetpack Compose)
when {
isLoading -> Spinner()
error != null -> ErrorView(message = error)
else -> Content()
}
解读: 三种框架的条件渲染本质相同——根据状态选择不同的 UI 描述。差异只在语法。
题目 8(选择题)
以下哪种写法适合"条件为真时渲染,为假时不渲染"?
A. if/else
B. 三元表达式
C. 逻辑与
D. switch
参考答案:C
解读: 逻辑与(a && b)适合条件为真时渲染,为假时不渲染。if/else 适合多分支互斥,三元适合两分支内联,switch 适合多分支。
题目 9(判断题)
条件渲染的组件在状态变化时一定会重新渲染。
参考答案:错误
解读: 条件渲染的组件在状态变化时不一定重新渲染。如果条件结果没变,且组件使用了 React.memo 或 EquatableView,组件可能跳过渲染。
题目 10(填空题)
SwiftUI 中 if/else 分支由 ______ 处理,不需要手动加 key。
参考答案:@ViewBuilder
解读: SwiftUI 的 @ViewBuilder 自动处理 if/else 分支的身份。如果需要强制重建,可以用 .id() 修饰符。
题目 11(简答题)
为什么条件渲染中,条件判断应该放在父组件而不是子组件?
参考答案: 如果条件判断放在子组件,父组件的其他 props 变化时,子组件会重新渲染,即使条件没变。
把条件判断放在父组件,条件为 true 时才渲染子组件,条件为 false 时不渲染子组件,避免不必要的重渲染。
// 错误:条件判断放在子组件
function Parent({ isLoading }) {
return <Child isLoading={isLoading} />
}
// 正确:条件判断放在父组件
function Parent({ isLoading }) {
if (isLoading) return <Spinner />
return <Child />
}
题目 12(代码分析题)
下面代码有什么问题?如何修正?
// TSX (React Native)
function View({ items, filter, sort }) {
return (
<View>
{items
.filter(item => item.category === filter)
.sort((a, b) => a[sort] – b[sort])
.length > 0 && (
<Content />
)}
</View>
)
}
参考答案: 复杂条件每次渲染都重新计算,性能浪费。
修正: 用 useMemo 缓存计算结果。
// TSX (React Native)
function View({ items, filter, sort }) {
const filteredItems = useMemo(() => {
return items
.filter(item => item.category === filter)
.sort((a, b) => a[sort] – b[sort])
}, [items, filter, sort])
return (
<View>
{filteredItems.length > 0 && <Content />}
</View>
)
}
题目 13(设计题)
设计一个页面状态系统,要求:
· 权限检查优先
· 加载中显示 Spinner
· 错误显示 Error
· 空数据显示 Empty
· 正常显示 Content
写出状态设计和条件渲染逻辑。
参考答案:
// TSX (React Native)
function Page({ isLoading, error, data, hasPermission, isEmpty }) {
// 优先级:权限 > 加载 > 错误 > 空态 > 正常
if (!hasPermission) return <NoPermission />
if (isLoading) return <Spinner />
if (error) return <Error message={error} />
if (isEmpty) return <Empty />
return <Content data={data} />
}
状态:isLoading、error、data、hasPermission、isEmpty
条件渲染:按优先级从上到下判断
解读: 用 if/else 表达优先级,从上到下依次判断,第一个为 true 的分支被渲染。这样保证任何时候只显示一个分支,不会出现多个状态同时显示的问题。
题目 14(设计题)
设计一个登录/注册切换表单,要求:
· 点击"登录"显示登录表单
· 点击"注册"显示注册表单
· 切换时清空输入框
写出状态设计、条件渲染、key 选择。
参考答案:
// TSX (React Native)
function AuthPage() {
const [mode, setMode] = useState('login')
return (
<View>
<View>
<Button title="登录" onPress={() => setMode('login')} />
<Button title="注册" onPress={() => setMode('register')} />
</View>
{mode === 'login' ? (
<LoginForm key="login" />
) : (
<RegisterForm key="register" />
)}
</View>
)
}
状态:mode
条件渲染:三元表达式
key:“login” 和 “register”
解读: 加 key 后,切换模式时框架销毁旧表单,创建新表单。表单的输入框状态被清空,符合用户预期。不加 key 时,如果两个表单结构相似,框架可能复用元素,输入框状态被保留,不符合用户预期。
题目 15(思考题)
为什么说"条件渲染是 视图 = 函数(状态) 在分支逻辑上的体现"?
参考答案: 视图 = 函数(状态) 的核心是"函数根据状态返回 UI 描述"。条件渲染把这个理念扩展到分支逻辑:
函数(状态) = if (状态A) UI描述A
else if (状态B) UI描述B
else UI描述C
条件渲染的三层含义:
从渲染管线角度:
1. 状态变化(isLoading: true → false)
2. 框架标记需要重新渲染
3. 重新执行函数,根据新状态选择分支
4. 得到新的 UI 描述
5. 框架对比新旧描述,如果有差异就通知底层更新
如果不用条件渲染,而是用命令式显示/隐藏:
1. 状态变化
2. 手动找到控件
3. 手动改 display 属性
4. 容易漏、容易错
终极结论: 条件渲染是 视图 = 函数(状态) 在分支逻辑上的自然延伸。状态是分支条件,函数是分支选择器,视图是分支结果。理解这一点,就能写出清晰、可维护、无 bug 的条件渲染。
九、下节预告
第 6 课:副作用与生命周期——如何管理副作用、如何与外部系统交互、如何避免副作用陷阱。

![[LangChain] 学习笔记(02):LCEL 链式调用与动态模型配置实战-171主机测评](https://www.171host.com/wp-content/uploads/2026/10/20261030203301-6ae4fefdb54f3-220x150.png)
![[LangChain] 学习笔记(02):LCEL 链式调用与动态模型配置实战-171主机测评](https://www.171host.com/wp-content/uploads/2026/10/20261030202745-6ae4fdc1556bf-220x150.png)
