Skip to content

React 条件判断

概述

条件渲染是 React 中最常用的功能之一,它让我们能够根据不同的条件显示不同的内容。本章将深入学习各种条件判断的方法、最佳实践以及性能优化技巧。

🔀 基础条件判断

if 语句

jsx
function ConditionalWithIf() {
  const [user, setUser] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  
  const login = () => {
    setLoading(true);
    setTimeout(() => {
      setUser({ name: '张三', role: 'admin' });
      setLoading(false);
    }, 1000);
  };
  
  const logout = () => {
    setUser(null);
  };
  
  // 使用 if 语句进行条件判断
  if (loading) {
    return (
      <div style={{ textAlign: 'center', padding: '50px' }}>
        <div>⏳ 登录中...</div>
      </div>
    );
  }
  
  if (user) {
    return (
      <div>
        <h2>欢迎,{user.name}!</h2>
        <p>您的角色:{user.role}</p>
        <button onClick={logout}>登出</button>
      </div>
    );
  }
  
  return (
    <div>
      <h2>请登录</h2>
      <button onClick={login}>登录</button>
    </div>
  );
}

三元运算符

jsx
function ConditionalWithTernary() {
  const [theme, setTheme] = React.useState('light');
  const [notifications, setNotifications] = React.useState([]);
  const [showSettings, setShowSettings] = React.useState(false);
  
  const addNotification = () => {
    const newNotification = {
      id: Date.now(),
      message: `通知 ${notifications.length + 1}`,
      type: Math.random() > 0.5 ? 'info' : 'warning'
    };
    setNotifications([...notifications, newNotification]);
  };
  
  const toggleTheme = () => {
    setTheme(theme === 'light' ? 'dark' : 'light');
  };
  
  const themeStyles = {
    light: { backgroundColor: '#fff', color: '#000' },
    dark: { backgroundColor: '#333', color: '#fff' }
  };
  
  return (
    <div style={{ ...themeStyles[theme], padding: '20px', minHeight: '400px' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <h2>条件渲染演示</h2>
        
        {/* 简单三元运算符 */}
        <button onClick={toggleTheme}>
          {theme === 'light' ? '🌙 深色模式' : '☀️ 浅色模式'}
        </button>
      </div>
      
      <div style={{ marginBottom: '20px' }}>
        <button onClick={addNotification} style={{ marginRight: '10px' }}>
          添加通知
        </button>
        <button onClick={() => setShowSettings(!showSettings)}>
          {showSettings ? '隐藏设置' : '显示设置'}
        </button>
      </div>
      
      {/* 嵌套三元运算符 */}
      <div>
        {notifications.length === 0 ? (
          <p>暂无通知</p>
        ) : notifications.length === 1 ? (
          <p>您有 1 条新通知</p>
        ) : (
          <p>您有 {notifications.length} 条新通知</p>
        )}
      </div>
      
      {/* 条件显示设置面板 */}
      {showSettings ? (
        <div style={{
          border: '1px solid #ddd',
          padding: '15px',
          marginTop: '20px',
          borderRadius: '5px'
        }}>
          <h3>设置面板</h3>
          <label>
            <input 
              type="checkbox" 
              checked={theme === 'dark'}
              onChange={toggleTheme}
            />
            深色模式
          </label>
        </div>
      ) : null}
      
      {/* 通知列表 */}
      <div style={{ marginTop: '20px' }}>
        {notifications.map(notification => (
          <div
            key={notification.id}
            style={{
              padding: '10px',
              margin: '5px 0',
              backgroundColor: notification.type === 'warning' ? '#fff3cd' : '#d1ecf1',
              color: notification.type === 'warning' ? '#856404' : '#0c5460',
              borderRadius: '4px'
            }}
          >
            {notification.type === 'warning' ? '⚠️' : 'ℹ️'} {notification.message}
          </div>
        ))}
      </div>
    </div>
  );
}

逻辑与运算符

jsx
function ConditionalWithLogicalAnd() {
  const [user, setUser] = React.useState({ 
    name: '张三', 
    isVip: true, 
    credits: 150,
    hasNotifications: true,
    unreadCount: 5
  });
  
  const [showModal, setShowModal] = React.useState(false);
  const [errors, setErrors] = React.useState([]);
  
  const addError = () => {
    setErrors([...errors, `错误 ${errors.length + 1}: 这是一个示例错误`]);
  };
  
  const clearErrors = () => {
    setErrors([]);
  };
  
  return (
    <div style={{ padding: '20px' }}>
      <h2>逻辑与运算符演示</h2>
      
      {/* 基础条件显示 */}
      {user && (
        <div style={{ marginBottom: '20px' }}>
          <h3>用户信息</h3>
          <p>姓名: {user.name}</p>
          
          {/* VIP 徽章 */}
          {user.isVip && (
            <span style={{
              backgroundColor: '#ffd700',
              color: '#000',
              padding: '2px 8px',
              borderRadius: '10px',
              fontSize: '12px'
            }}>
              👑 VIP
            </span>
          )}
          
          {/* 积分显示 */}
          {user.credits > 100 && (
            <div style={{ color: 'green', marginTop: '10px' }}>
              🎉 恭喜!您的积分已超过 100 分!
            </div>
          )}
          
          {/* 通知提醒 */}
          {user.hasNotifications && user.unreadCount > 0 && (
            <div style={{
              backgroundColor: '#ff4757',
              color: 'white',
              padding: '10px',
              borderRadius: '5px',
              marginTop: '10px'
            }}>
              📬 您有 {user.unreadCount} 条未读通知
            </div>
          )}
        </div>
      )}
      
      {/* 错误显示 */}
      {errors.length > 0 && (
        <div style={{ marginBottom: '20px' }}>
          <h3>错误列表</h3>
          {errors.map((error, index) => (
            <div key={index} style={{
              backgroundColor: '#f8d7da',
              color: '#721c24',
              padding: '10px',
              margin: '5px 0',
              borderRadius: '4px',
              border: '1px solid #f5c6cb'
            }}>
              ❌ {error}
            </div>
          ))}
          <button onClick={clearErrors} style={{
            backgroundColor: '#dc3545',
            color: 'white',
            border: 'none',
            padding: '8px 16px',
            borderRadius: '4px'
          }}>
            清除所有错误
          </button>
        </div>
      )}
      
      <div>
        <button onClick={addError} style={{ marginRight: '10px' }}>
          添加错误
        </button>
        <button onClick={() => setShowModal(true)}>
          显示模态框
        </button>
      </div>
      
      {/* 模态框 */}
      {showModal && (
        <div style={{
          position: 'fixed',
          top: 0,
          left: 0,
          right: 0,
          bottom: 0,
          backgroundColor: 'rgba(0,0,0,0.5)',
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          zIndex: 1000
        }}>
          <div style={{
            backgroundColor: 'white',
            padding: '30px',
            borderRadius: '8px',
            maxWidth: '400px',
            width: '90%'
          }}>
            <h3>模态框标题</h3>
            <p>这是一个条件显示的模态框。</p>
            <button 
              onClick={() => setShowModal(false)}
              style={{
                backgroundColor: '#007bff',
                color: 'white',
                border: 'none',
                padding: '10px 20px',
                borderRadius: '4px'
              }}
            >
              关闭
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

🎯 复杂条件判断

Switch 语句模拟

jsx
function ComplexConditionals() {
  const [status, setStatus] = React.useState('idle');
  const [userRole, setUserRole] = React.useState('guest');
  const [errorType, setErrorType] = React.useState(null);
  
  // 状态渲染函数
  const renderStatus = () => {
    switch (status) {
      case 'loading':
        return (
          <div style={{ textAlign: 'center', color: '#007bff' }}>
            ⏳ 正在加载...
          </div>
        );
      case 'success':
        return (
          <div style={{ textAlign: 'center', color: '#28a745' }}>
            ✅ 操作成功完成
          </div>
        );
      case 'error':
        return (
          <div style={{ textAlign: 'center', color: '#dc3545' }}>
            ❌ 操作失败,请重试
          </div>
        );
      case 'idle':
      default:
        return (
          <div style={{ textAlign: 'center', color: '#6c757d' }}>
            💤 等待操作
          </div>
        );
    }
  };
  
  // 用户界面渲染
  const renderUserInterface = () => {
    const interfaces = {
      admin: (
        <div style={{ backgroundColor: '#e7f3ff', padding: '20px', borderRadius: '8px' }}>
          <h3>👑 管理员控制台</h3>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '10px' }}>
            <button>用户管理</button>
            <button>系统设置</button>
            <button>数据统计</button>
            <button>安全中心</button>
          </div>
        </div>
      ),
      moderator: (
        <div style={{ backgroundColor: '#fff3e0', padding: '20px', borderRadius: '8px' }}>
          <h3>🛡️ 版主面板</h3>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '10px' }}>
            <button>内容审核</button>
            <button>用户举报</button>
            <button>社区管理</button>
            <button>数据报告</button>
          </div>
        </div>
      ),
      vip: (
        <div style={{ backgroundColor: '#f3e5f5', padding: '20px', borderRadius: '8px' }}>
          <h3>💎 VIP 专区</h3>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '10px' }}>
            <button>专属服务</button>
            <button>高级功能</button>
            <button>优先支持</button>
            <button>特权礼品</button>
          </div>
        </div>
      ),
      user: (
        <div style={{ backgroundColor: '#e8f5e8', padding: '20px', borderRadius: '8px' }}>
          <h3>👤 用户中心</h3>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '10px' }}>
            <button>个人资料</button>
            <button>订单管理</button>
            <button>收藏夹</button>
            <button>设置</button>
          </div>
        </div>
      ),
      guest: (
        <div style={{ backgroundColor: '#f8f9fa', padding: '20px', borderRadius: '8px' }}>
          <h3>🚪 访客模式</h3>
          <p>请登录以获取完整功能</p>
          <div style={{ display: 'flex', gap: '10px' }}>
            <button style={{ backgroundColor: '#007bff', color: 'white', border: 'none', padding: '10px 20px', borderRadius: '4px' }}>
              登录
            </button>
            <button style={{ backgroundColor: '#28a745', color: 'white', border: 'none', padding: '10px 20px', borderRadius: '4px' }}>
              注册
            </button>
          </div>
        </div>
      )
    };
    
    return interfaces[userRole] || interfaces.guest;
  };
  
  // 错误类型处理
  const renderError = () => {
    if (!errorType) return null;
    
    const errorMessages = {
      network: {
        icon: '🌐',
        title: '网络错误',
        message: '请检查您的网络连接',
        color: '#ff6b6b'
      },
      auth: {
        icon: '🔐',
        title: '认证失败',
        message: '请重新登录',
        color: '#ffa502'
      },
      permission: {
        icon: '🚫',
        title: '权限不足',
        message: '您没有执行此操作的权限',
        color: '#ff4757'
      },
      server: {
        icon: '🔧',
        title: '服务器错误',
        message: '服务器暂时不可用,请稍后重试',
        color: '#5f27cd'
      }
    };
    
    const error = errorMessages[errorType];
    
    return (
      <div style={{
        backgroundColor: error.color + '20',
        border: `1px solid ${error.color}`,
        borderRadius: '8px',
        padding: '15px',
        margin: '20px 0'
      }}>
        <div style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
          <span style={{ fontSize: '24px', marginRight: '10px' }}>{error.icon}</span>
          <h4 style={{ margin: 0, color: error.color }}>{error.title}</h4>
        </div>
        <p style={{ margin: 0, color: '#333' }}>{error.message}</p>
        <button 
          onClick={() => setErrorType(null)}
          style={{
            marginTop: '10px',
            backgroundColor: error.color,
            color: 'white',
            border: 'none',
            padding: '8px 16px',
            borderRadius: '4px'
          }}
        >
          关闭
        </button>
      </div>
    );
  };
  
  return (
    <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
      <h2>复杂条件判断演示</h2>
      
      {/* 状态控制 */}
      <div style={{ marginBottom: '20px' }}>
        <h3>状态控制</h3>
        <div style={{ display: 'flex', gap: '10px', marginBottom: '15px' }}>
          {['idle', 'loading', 'success', 'error'].map(s => (
            <button 
              key={s}
              onClick={() => setStatus(s)}
              style={{
                backgroundColor: status === s ? '#007bff' : '#f8f9fa',
                color: status === s ? 'white' : '#333',
                border: '1px solid #ddd',
                padding: '8px 16px',
                borderRadius: '4px'
              }}
            >
              {s}
            </button>
          ))}
        </div>
        {renderStatus()}
      </div>
      
      {/* 用户角色切换 */}
      <div style={{ marginBottom: '20px' }}>
        <h3>用户角色</h3>
        <select 
          value={userRole} 
          onChange={(e) => setUserRole(e.target.value)}
          style={{ padding: '8px', marginBottom: '15px' }}
        >
          <option value="guest">访客</option>
          <option value="user">普通用户</option>
          <option value="vip">VIP用户</option>
          <option value="moderator">版主</option>
          <option value="admin">管理员</option>
        </select>
        {renderUserInterface()}
      </div>
      
      {/* 错误类型演示 */}
      <div>
        <h3>错误处理</h3>
        <div style={{ display: 'flex', gap: '10px', marginBottom: '15px' }}>
          {['network', 'auth', 'permission', 'server'].map(type => (
            <button 
              key={type}
              onClick={() => setErrorType(type)}
              style={{
                backgroundColor: '#dc3545',
                color: 'white',
                border: 'none',
                padding: '8px 16px',
                borderRadius: '4px'
              }}
            >
              {type} 错误
            </button>
          ))}
        </div>
        {renderError()}
      </div>
    </div>
  );
}

多重条件组合

jsx
function MultipleConditions() {
  const [user, setUser] = React.useState({
    isLoggedIn: false,
    isVip: false,
    credits: 0,
    level: 1
  });
  
  const [appState, setAppState] = React.useState({
    isOnline: true,
    maintenance: false,
    feature: {
      chatEnabled: true,
      paymentEnabled: true,
      analyticsEnabled: false
    }
  });
  
  const toggleLogin = () => {
    setUser(prev => ({ 
      ...prev, 
      isLoggedIn: !prev.isLoggedIn,
      credits: prev.isLoggedIn ? 0 : 150,
      level: prev.isLoggedIn ? 1 : 3
    }));
  };
  
  const toggleVip = () => {
    setUser(prev => ({ ...prev, isVip: !prev.isVip }));
  };
  
  const toggleMaintenance = () => {
    setAppState(prev => ({ ...prev, maintenance: !prev.maintenance }));
  };
  
  const canAccessFeature = (feature) => {
    return user.isLoggedIn && 
           appState.isOnline && 
           !appState.maintenance &&
           appState.feature[feature];
  };
  
  const canAccessVipFeature = () => {
    return user.isLoggedIn && 
           user.isVip && 
           user.level >= 3 &&
           appState.isOnline;
  };
  
  const showPaymentOptions = () => {
    return user.isLoggedIn && 
           user.credits < 100 &&
           canAccessFeature('paymentEnabled');
  };
  
  return (
    <div style={{ padding: '20px' }}>
      <h2>多重条件判断</h2>
      
      {/* 控制面板 */}
      <div style={{ 
        backgroundColor: '#f8f9fa', 
        padding: '15px', 
        borderRadius: '8px',
        marginBottom: '20px'
      }}>
        <h3>控制面板</h3>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px' }}>
          <button onClick={toggleLogin}>
            {user.isLoggedIn ? '登出' : '登录'}
          </button>
          <button onClick={toggleVip} disabled={!user.isLoggedIn}>
            {user.isVip ? '取消VIP' : '开通VIP'}
          </button>
          <button onClick={toggleMaintenance}>
            {appState.maintenance ? '结束维护' : '开始维护'}
          </button>
        </div>
        
        <div style={{ marginTop: '10px', fontSize: '14px' }}>
          <span>在线: {appState.isOnline ? '✅' : '❌'}</span>
          <span style={{ marginLeft: '20px' }}>
            维护模式: {appState.maintenance ? '🔧' : '✅'}
          </span>
        </div>
      </div>
      
      {/* 用户状态显示 */}
      <div style={{ marginBottom: '20px' }}>
        {user.isLoggedIn ? (
          <div style={{ 
            backgroundColor: '#d4edda', 
            padding: '15px', 
            borderRadius: '8px',
            border: '1px solid #c3e6cb'
          }}>
            <h3>用户信息</h3>
            <p>状态: 已登录 {user.isVip && '👑 VIP'}</p>
            <p>积分: {user.credits}</p>
            <p>等级: {user.level}</p>
          </div>
        ) : (
          <div style={{ 
            backgroundColor: '#f8d7da', 
            padding: '15px', 
            borderRadius: '8px',
            border: '1px solid #f5c6cb'
          }}>
            <h3>未登录</h3>
            <p>请登录以使用全部功能</p>
          </div>
        )}
      </div>
      
      {/* 维护模式提示 */}
      {appState.maintenance && (
        <div style={{
          backgroundColor: '#fff3cd',
          border: '1px solid #ffeaa7',
          padding: '15px',
          borderRadius: '8px',
          marginBottom: '20px'
        }}>
          🔧 系统正在维护中,部分功能可能不可用
        </div>
      )}
      
      {/* 功能区域 */}
      <div style={{ 
        display: 'grid', 
        gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', 
        gap: '15px' 
      }}>
        {/* 聊天功能 */}
        <div style={{
          border: '1px solid #ddd',
          borderRadius: '8px',
          padding: '15px',
          opacity: canAccessFeature('chatEnabled') ? 1 : 0.5
        }}>
          <h4>💬 聊天功能</h4>
          {canAccessFeature('chatEnabled') ? (
            <div>
              <p>聊天功能可用</p>
              <button>开始聊天</button>
            </div>
          ) : (
            <div>
              <p style={{ color: '#666' }}>
                {!user.isLoggedIn && '请先登录'}
                {user.isLoggedIn && appState.maintenance && '维护中暂时不可用'}
                {user.isLoggedIn && !appState.feature.chatEnabled && '功能已禁用'}
              </p>
            </div>
          )}
        </div>
        
        {/* VIP功能 */}
        <div style={{
          border: '1px solid #ddd',
          borderRadius: '8px',
          padding: '15px',
          opacity: canAccessVipFeature() ? 1 : 0.5
        }}>
          <h4>👑 VIP专属功能</h4>
          {canAccessVipFeature() ? (
            <div>
              <p>VIP功能可用</p>
              <button>访问VIP区域</button>
            </div>
          ) : (
            <div>
              <p style={{ color: '#666' }}>
                {!user.isLoggedIn && '请先登录'}
                {user.isLoggedIn && !user.isVip && '需要VIP会员'}
                {user.isLoggedIn && user.isVip && user.level < 3 && '等级不足'}
                {user.isLoggedIn && user.isVip && !appState.isOnline && '网络不可用'}
              </p>
            </div>
          )}
        </div>
        
        {/* 支付选项 */}
        <div style={{
          border: '1px solid #ddd',
          borderRadius: '8px',
          padding: '15px',
          opacity: showPaymentOptions() ? 1 : 0.5
        }}>
          <h4>💳 充值中心</h4>
          {showPaymentOptions() ? (
            <div>
              <p>积分不足,需要充值</p>
              <button>立即充值</button>
            </div>
          ) : user.isLoggedIn && user.credits >= 100 ? (
            <div>
              <p style={{ color: 'green' }}>积分充足</p>
            </div>
          ) : (
            <div>
              <p style={{ color: '#666' }}>
                {!user.isLoggedIn && '请先登录'}
                {user.isLoggedIn && !canAccessFeature('paymentEnabled') && '支付功能不可用'}
              </p>
            </div>
          )}
        </div>
      </div>
      
      {/* 条件组合示例 */}
      <div style={{ marginTop: '30px' }}>
        <h3>条件组合示例</h3>
        <div style={{ fontSize: '14px', backgroundColor: '#f8f9fa', padding: '15px', borderRadius: '8px' }}>
          <p><strong>聊天功能条件:</strong> 已登录 && 在线 && 非维护模式 && 功能开启</p>
          <p><strong>VIP功能条件:</strong> 已登录 && VIP会员 && 等级≥3 && 在线</p>
          <p><strong>充值提示条件:</strong> 已登录 && 积分&lt;100 && 支付功能开启</p>
        </div>
      </div>
    </div>
  );
}

📝 本章小结

通过本章学习,你应该掌握了:

条件判断方法

  • ✅ if 语句:适用于复杂逻辑
  • ✅ 三元运算符:简洁的二元判断
  • ✅ 逻辑与运算符:简单的存在性检查
  • ✅ Switch 模拟:多分支条件处理

最佳实践

  1. 选择合适的方法:根据复杂度选择判断方式
  2. 避免深层嵌套:使用早期返回和提取函数
  3. 条件组合:合理组织多重条件逻辑
  4. 性能优化:避免不必要的条件计算
  5. 可读性优先:保持代码清晰易懂

继续学习下一章 - React 自定义 Hook

本站内容仅供学习和研究使用。