01-React基础入门——06-条件渲染
2026/6/6 12:54:19 网站建设 项目流程

条件渲染

一、什么是条件渲染?

条件渲染是指根据不同的条件(如状态、属性、用户输入等)来决定渲染哪些 UI 元素。这是 React 中最常见的模式之一。

核心概念

  • 使用 JavaScript 条件语句(ifswitch)或运算符(&&? :)来决定渲染内容
  • React 的声明式特性使得条件渲染非常直观
  • 可以实现:登录/退出按钮、权限控制、加载状态、表单验证提示等

二、条件渲染的 5 种方式

2.1 if/else 语句

最适合逻辑复杂、代码块较长的场景。

function UserGreeting({ isLoggedIn, user }) { if (isLoggedIn && user) { return ( <div className="welcome"> <h1>欢迎回来,{user.name}!</h1> <p>上次登录:{user.lastLogin}</p> </div> ); } else if (isLoggedIn) { return <h1>欢迎回来!</h1>; } else { return ( <div className="login-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 className="notification"> 消息 {count > 0 && <span className="badge">{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 className="status-pending"> ⏳ 订单待处理 <button>取消订单</button> </div> ); case 'processing': return ( <div className="status-processing"> 🔄 订单处理中 <ProgressBar percent={50} /> </div> ); case 'shipped': return ( <div className="status-shipped"> 📦 已发货 <TrackingNumber number="SF123456789" /> </div> ); case 'delivered': return ( <div className="status-delivered"> ✅ 已送达 <ConfirmReceiptButton /> </div> ); default: return <div className="status-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 className="ad-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 className="auth-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} requiredRole="editor" fallback={<NoPermission />}> <EditButton /> </PermissionGate>

4.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> ); }

七、练习题

基础题

  1. 实现一个ToggleMessage组件:点击按钮切换显示/隐藏一段文字
  2. 实现一个ScoreRating:根据分数(0-100)显示"优秀/良好/及格/不及格"

进阶题

  1. 实现一个TabSwitcher:支持 3 个标签页,点击切换内容
  2. 实现一个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 className="tabs"> {tabs.map((tab, index) => ( <button key={index} onClick={() => setActiveTab(index)} style={{ fontWeight: activeTab === index ? 'bold' : 'normal' }} > {tab} </button> ))} </div> <div className="tab-content"> {contents[activeTab]} </div> </div> ); }

八、小结

方式适用场景优点缺点
if/else复杂逻辑、代码块长清晰易读不能内联
三元运算符简单二分支简洁嵌套难读
&& 运算符条件性显示最简洁注意 0 陷阱
switch多分支结构清晰代码冗长
枚举映射多分支、逻辑简单最优雅需要额外定义

核心要点

  • 根据场景选择合适的方式
  • 避免 JSX 中嵌套过深的条件逻辑
  • 提前返回让代码更清晰
  • 注意数字 0 和字符串 ‘false’ 的陷阱
  • 复杂逻辑提取为函数或单独组件

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询