01-React基础入门——06-条件渲染

张开发
2026/6/6 12:54:22 15 分钟阅读

分享文章

01-React基础入门——06-条件渲染
条件渲染一、什么是条件渲染条件渲染是指根据不同的条件如状态、属性、用户输入等来决定渲染哪些 UI 元素。这是 React 中最常见的模式之一。核心概念使用 JavaScript 条件语句if、switch或运算符、? :来决定渲染内容React 的声明式特性使得条件渲染非常直观可以实现登录/退出按钮、权限控制、加载状态、表单验证提示等二、条件渲染的 5 种方式2.1 if/else 语句最适合逻辑复杂、代码块较长的场景。function UserGreeting({ isLoggedIn, user }) { if (isLoggedIn user) { return ( div classNamewelcome h1欢迎回来{user.name}/h1 p上次登录{user.lastLogin}/p /div ); } else if (isLoggedIn) { return h1欢迎回来/h1; } else { return ( div classNamelogin-prompt h1请先登录/h1 button去登录/button /div ); } }2.2 三元运算符 (condition ? expr1 : expr2)最适合简单的二分支场景简洁直观。function StatusBadge({ status }) { return ( span className{badge ${status active ? badge-success : badge-danger}} {status active ? 在线 : 离线} /span ); } // 嵌套使用谨慎可读性会下降 function ComplexStatus({ status }) { return ( div {status loading ? ( Spinner / ) : status error ? ( ErrorMessage / ) : ( SuccessMessage / )} /div ); }2.3 逻辑与运算符 ()最适合满足条件才渲染否则什么都不渲染的场景。function NotificationBadge({ count }) { return ( div classNamenotification 消息 {count 0 span classNamebadge{count}/span} /div ); } function AdminPanel({ user }) { return ( div h1仪表盘/h1 {user.isAdmin AdminTools /} {user.canDelete DeleteButton /} {user.canEdit EditButton /} /div ); }2.4 switch 语句最适合多分支、每种分支逻辑较复杂的场景。function OrderStatus({ status }) { switch (status) { case pending: return ( div classNamestatus-pending ⏳ 订单待处理 button取消订单/button /div ); case processing: return ( div classNamestatus-processing 订单处理中 ProgressBar percent{50} / /div ); case shipped: return ( div classNamestatus-shipped 已发货 TrackingNumber numberSF123456789 / /div ); case delivered: return ( div classNamestatus-delivered ✅ 已送达 ConfirmReceiptButton / /div ); default: return div classNamestatus-unknown❓ 未知状态/div; } }2.5 枚举对象映射最优雅的多分支方案适合分支较多且逻辑简单的场景。const STATUS_CONFIG { pending: { icon: ⏳, text: 待处理, className: status-pending, actions: [cancel] }, processing: { icon: , text: 处理中, className: status-processing, actions: [] }, completed: { icon: ✅, text: 已完成, className: status-completed, actions: [review, reorder] } }; function OrderStatus({ status }) { const config STATUS_CONFIG[status] || STATUS_CONFIG.pending; return ( div className{config.className} span{config.icon}/span span{config.text}/span /div ); } // 更高级的用法直接映射到组件 const COMPONENT_MAP { loading: LoadingSpinner, error: ErrorMessage, success: SuccessMessage, empty: EmptyState }; function AsyncRenderer({ status, ...props }) { const Component COMPONENT_MAP[status]; return Component ? Component {...props} / : null; }三、阻止渲染返回 null某些场景下我们希望组件被调用但不渲染任何内容。function AdBanner({ user, isVisible }) { // VIP 用户不显示广告 if (user.isVIP) { return null; } // 手动隐藏 if (!isVisible) { return null; } return ( div classNamead-banner 限时优惠点击购买 /div ); }注意事项返回null的组件仍然会执行生命周期useEffect等父组件的useEffect不会因为子组件返回 null 而跳过返回 null 的组件不会被渲染到 DOM 中四、实战案例4.1 登录/注册切换function AuthPage() { const [mode, setMode] useState(login); // login | register | forgot const renderForm () { switch (mode) { case login: return LoginForm onSwitch{setMode} /; case register: return RegisterForm onSwitch{setMode} /; case forgot: return ForgotPasswordForm onSwitch{setMode} /; default: return LoginForm onSwitch{setMode} /; } }; return ( div classNameauth-container {renderForm()} /div ); }4.2 数据加载状态function DataFetcher({ url }) { const [state, setState] useState({ status: idle, // idle | loading | success | error data: null, error: null }); useEffect(() { setState({ status: loading, data: null, error: null }); fetch(url) .then(res res.json()) .then(data setState({ status: success, data, error: null })) .catch(error setState({ status: error, data: null, error })); }, [url]); // 条件渲染的清晰写法 if (state.status loading) { return LoadingSpinner /; } if (state.status error) { return ErrorMessage error{state.error} /; } if (state.status success !state.data) { return EmptyState /; } return DataDisplay data{state.data} /; }4.3 权限控制function PermissionGate({ user, requiredRole, children, fallback }) { const hasPermission () { const roleLevel { admin: 3, editor: 2, viewer: 1 }; return (roleLevel[user.role] || 0) (roleLevel[requiredRole] || 0); }; return hasPermission() ? children : (fallback || null); } // 使用 PermissionGate user{currentUser} requiredRoleeditor fallback{NoPermission /} EditButton / /PermissionGate4.4 响应式布局根据屏幕尺寸function ResponsiveLayout() { const [isMobile, setIsMobile] useState(window.innerWidth 768); useEffect(() { const handleResize () setIsMobile(window.innerWidth 768); window.addEventListener(resize, handleResize); return () window.removeEventListener(resize, handleResize); }, []); return ( div {isMobile ? ( MobileNavigation / ) : ( DesktopNavigation / )} {/* 只在桌面显示侧边栏 */} {!isMobile Sidebar /} MainContent / /div ); }五、常见陷阱与最佳实践5.1 陷阱0 被渲染// ❌ 错误当 count 0 时会渲染数字 0 {count span有 {count} 条消息/span} // ✅ 正确明确的条件判断 {count 0 span有 {count} 条消息/span} // ✅ 或者使用三元运算符 {count ? span有 {count} 条消息/span : null}5.2 陷阱字符串 ‘false’ 被渲染// ❌ 错误false 是真值会渲染 {isVisible div内容/div} // 假设 isVisible false // ✅ 正确确保是布尔值 {!!isVisible div内容/div} {Boolean(isVisible) div内容/div}5.3 最佳实践提取复杂逻辑// ❌ 不推荐JSX 中写复杂逻辑 function Component({ user, data, loading }) { return ( div {loading ? ( Spinner / ) : user ? ( user.isVIP ? ( VIPDashboard data{data} / ) : ( RegularDashboard data{data} / ) ) : ( LoginPrompt / )} /div ); } // ✅ 推荐提取为函数 function Component({ user, data, loading }) { const renderContent () { if (loading) return Spinner /; if (!user) return LoginPrompt /; if (user.isVIP) return VIPDashboard data{data} /; return RegularDashboard data{data} /; }; return div{renderContent()}/div; }5.4 最佳实践提前返回// ✅ 提前返回让代码更清晰 function UserProfile({ user, loading, error }) { if (loading) return LoadingSpinner /; if (error) return ErrorMessage error{error} /; if (!user) return LoginPrompt /; return ( div h1{user.name}/h1 p{user.email}/p /div ); }六、性能优化6.1 使用 React.memo 避免不必要的重渲染const ExpensiveComponent React.memo(({ data }) { // 复杂计算 return div{/* ... */}/div; }); function Parent({ showExpensive }) { return ( div {/* 条件渲染不影响 ExpensiveComponent 的 memo 优化 */} {showExpensive ExpensiveComponent data{data} /} /div ); }6.2 懒加载条件组件const LazyComponent lazy(() import(./HeavyComponent)); function App({ showHeavy }) { return ( Suspense fallback{div加载中.../div} {showHeavy LazyComponent /} /Suspense ); }七、练习题基础题实现一个ToggleMessage组件点击按钮切换显示/隐藏一段文字实现一个ScoreRating根据分数0-100显示优秀/良好/及格/不及格进阶题实现一个TabSwitcher支持 3 个标签页点击切换内容实现一个FormWizard多步骤表单根据当前步骤显示不同表单参考答案// 1. ToggleMessage function ToggleMessage() { const [visible, setVisible] useState(false); return ( div button onClick{() setVisible(!visible)} {visible ? 隐藏 : 显示} /button {visible p这是一段可切换显示的文字/p} /div ); } // 2. ScoreRating function ScoreRating({ score }) { const getRating () { if (score 90) return { text: 优秀, color: green }; if (score 75) return { text: 良好, color: blue }; if (score 60) return { text: 及格, color: orange }; return { text: 不及格, color: red }; }; const { text, color } getRating(); return span style{{ color }}评分{text} ({score}分)/span; } // 3. TabSwitcher function TabSwitcher() { const [activeTab, setActiveTab] useState(0); const tabs [Tab 1, Tab 2, Tab 3]; const contents [内容 1, 内容 2, 内容 3]; return ( div div classNametabs {tabs.map((tab, index) ( button key{index} onClick{() setActiveTab(index)} style{{ fontWeight: activeTab index ? bold : normal }} {tab} /button ))} /div div classNametab-content {contents[activeTab]} /div /div ); }八、小结方式适用场景优点缺点if/else复杂逻辑、代码块长清晰易读不能内联三元运算符简单二分支简洁嵌套难读 运算符条件性显示最简洁注意 0 陷阱switch多分支结构清晰代码冗长枚举映射多分支、逻辑简单最优雅需要额外定义核心要点根据场景选择合适的方式避免 JSX 中嵌套过深的条件逻辑提前返回让代码更清晰注意数字 0 和字符串 ‘false’ 的陷阱复杂逻辑提取为函数或单独组件

更多文章