function UserGreeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <h1>欢迎回来!</h1>;
}
return <h1>请先登录。</h1>;
}
function LoginControl() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const handleLogin = () => {
setIsLoggedIn(true);
};
const handleLogout = () => {
setIsLoggedIn(false);
};
return (
<div>
<UserGreeting isLoggedIn={isLoggedIn} />
{isLoggedIn ? (
<button onClick={handleLogout}>退出</button>
) : (
<button onClick={handleLogin}>登录</button>
)}
</div>
);
}
function LoginButton(props) {
return (
<button onClick={props.onClick}>
登录
</button>
);
}
function LogoutButton(props) {
return (
<button onClick={props.onClick}>
退出
</button>
);
}
function LoginControlWithVariable() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const handleLoginClick = () => {
setIsLoggedIn(true);
};
const handleLogoutClick = () => {
setIsLoggedIn(false);
};
// 使用变量存储元素
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={handleLogoutClick} />;
} else {
button = <LoginButton onClick={handleLoginClick} />;
}
return (
<div>
<p>用户状态: {isLoggedIn ? '已登录' : '未登录'}</p>
{button}
</div>
);
}
当条件为true时,渲染右侧的元素;条件为false时,什么都不渲染。
function MessageList(props) {
const messages = props.messages;
return (
<div>
<h3>消息列表</h3>
{messages.length > 0 &&
<p>
你有 {messages.length} 条未读消息。
</p>
}
<ul>
{messages.map(message => (
<li key={message.id}>{message.text}</li>
))}
</ul>
</div>
);
}
// 使用组件
const messages = [
{ id: 1, text: '消息1' },
{ id: 2, text: '消息2' }
];
// 渲染 MessageList 组件
<MessageList messages={messages} />
function Notification(props) {
const isImportant = props.isImportant;
const message = props.message;
return (
<div className={`notification ${isImportant ? 'important' : 'normal'}`}>
{isImportant ? (
<div>
<strong><i className="fas fa-exclamation-circle"></i> 重要: </strong>
{message}
</div>
) : (
<div>
<i className="fas fa-info-circle"></i> 通知: {message}
</div>
)}
</div>
);
}
// 更复杂的三元运算符嵌套(不推荐)
function ComplexTernaryExample() {
const [status, setStatus] = useState('loading');
const [data, setData] = useState(null);
const [error, setError] = useState(null);
// 不推荐的写法:嵌套过深难以阅读
const renderContent = () => {
return status === 'loading' ? (
<div>加载中...</div>
) : status === 'error' ? (
<div>错误: {error}</div>
) : (
<div>数据: {JSON.stringify(data)}</div>
);
};
return (
<div>
{renderContent()}
</div>
);
}
在某些情况下,你可能希望隐藏组件,即使它已经被其他组件渲染。这时可以让 render 方法直接返回 null,而不进行任何渲染。
function WarningBanner(props) {
if (!props.warn) {
return null; // 不渲染任何内容
}
return (
<div className="warning">
<i className="fas fa-exclamation-triangle"></i>
警告!
</div>
);
}
function Page() {
const [showWarning, setShowWarning] = useState(true);
const toggleWarning = () => {
setShowWarning(!showWarning);
};
return (
<div>
<WarningBanner warn={showWarning} />
<button onClick={toggleWarning}>
{showWarning ? '隐藏警告' : '显示警告'}
</button>
</div>
);
}
| 方法 | 语法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| if语句 | if (condition) { ... } else { ... } |
组件级别的条件渲染 | 清晰易读,适合复杂逻辑 | 需要在组件外部或函数内部使用 |
| 三元运算符 | condition ? true : false |
简单的二选一渲染 | 简洁,可在JSX内联使用 | 嵌套时难以阅读 |
| 逻辑与运算符 | condition && element |
条件为真时渲染元素 | 非常简洁 | 条件为假时渲染0的问题 |
| 元素变量 | let element = condition ? a : b |
需要复用条件结果 | 提高代码可读性 | 增加变量声明 |
| 立即执行函数 | {(() => { ... })()} |
复杂条件逻辑 | 灵活,可包含复杂逻辑 | 语法复杂,影响可读性 |
function UserProfile({ userId }) {
const [loading, setLoading] = useState(true);
const [user, setUser] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
fetchUser(userId);
}, [userId]);
const fetchUser = async (id) => {
try {
setLoading(true);
// 模拟API调用
const response = await fetch(`/api/users/${id}`);
const data = await response.json();
setUser(data);
setError(null);
} catch (err) {
setError('加载用户数据失败');
setUser(null);
} finally {
setLoading(false);
}
};
// 使用条件渲染处理不同状态
if (loading) {
return (
<div className="loading-spinner">
<i className="fas fa-spinner fa-spin"></i>
加载中...
</div>
);
}
if (error) {
return (
<div className="error-message">
<i className="fas fa-exclamation-circle"></i>
{error}
</div>
);
}
if (!user) {
return (
<div className="no-data">
未找到用户信息
</div>
);
}
return (
<div className="user-profile">
<h2>{user.name}</h2>
<p>邮箱: {user.email}</p>
<p>角色: {user.role}</p>
</div>
);
}
// 权限控制组件
function ProtectedRoute({ children, requiredRole }) {
const { user, loading } = useAuth();
if (loading) {
return <div>检查权限中...</div>;
}
// 检查用户是否登录
if (!user) {
return (
<div className="unauthorized">
<h3>需要登录</h3>
<p>请先登录访问此页面</p>
<a href="/login">前往登录</a>
</div>
);
}
// 检查用户角色
if (requiredRole && user.role !== requiredRole) {
return (
<div className="forbidden">
<h3>权限不足</h3>
<p>您没有权限访问此页面</p>
</div>
);
}
// 权限检查通过,渲染子组件
return children;
}
// 使用示例
function AdminPanel() {
return (
<ProtectedRoute requiredRole="admin">
<div>
<h1>管理员面板</h1>
<p>只有管理员能看到这个内容</p>
{/* 管理员功能 */}
</div>
</ProtectedRoute>
);
}
function ProductList({ products, showOutOfStock, sortBy }) {
// 过滤产品
let filteredProducts = products;
if (!showOutOfStock) {
filteredProducts = products.filter(product => product.inStock);
}
// 排序产品
if (sortBy === 'price') {
filteredProducts = [...filteredProducts].sort((a, b) => a.price - b.price);
} else if (sortBy === 'name') {
filteredProducts = [...filteredProducts].sort((a, b) =>
a.name.localeCompare(b.name)
);
}
// 条件渲染:空列表处理
if (filteredProducts.length === 0) {
return (
<div className="empty-state">
<i className="fas fa-box-open"></i>
<h3>没有找到产品</h3>
<p>尝试调整筛选条件</p>
</div>
);
}
// 条件渲染:显示结果数量
return (
<div>
<div className="results-info">
找到 {filteredProducts.length} 个产品
{!showOutOfStock && (
<span className="info-text"> (已隐藏缺货产品)</span>
)}
</div>
<div className="product-grid">
{filteredProducts.map(product => (
<ProductCard
key={product.id}
product={product}
/>
))}
</div>
</div>
);
}
// 将复杂条件提取为专用组件
function StatusRenderer({ status, data, error }) {
switch (status) {
case 'loading':
return <LoadingSpinner />;
case 'error':
return <ErrorMessage error={error} />;
case 'empty':
return <EmptyState />;
case 'success':
return <DataDisplay data={data} />;
default:
return null;
}
}
// 在主组件中使用
function DataFetcher() {
const [status, setStatus] = useState('loading');
const [data, setData] = useState(null);
const [error, setError] = useState(null);
// ... 数据获取逻辑
return (
<div>
<StatusRenderer
status={status}
data={data}
error={error}
/>
</div>
);
}
// 定义状态常量
const Status = {
LOADING: 'loading',
SUCCESS: 'success',
ERROR: 'error',
EMPTY: 'empty'
};
function DataComponent() {
const [status, setStatus] = useState(Status.LOADING);
// 使用switch语句处理不同状态
const renderContent = () => {
switch (status) {
case Status.LOADING:
return <Loader />;
case Status.SUCCESS:
return <Data />;
case Status.ERROR:
return <Error />;
case Status.EMPTY:
return <Empty />;
default:
return null;
}
};
return (
<div>
{renderContent()}
</div>
);
}
// 自定义Hook处理加载状态
function useDataFetcher(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchData();
}, [url]);
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
return { data, loading, error };
}
// 使用自定义Hook
function UserComponent({ userId }) {
const { data: user, loading, error } = useDataFetcher(`/api/users/${userId}`);
if (loading) return <Loader />;
if (error) return <Error message={error} />;
if (!user) return <Empty message="用户不存在" />;
return (
<div>
<h2>{user.name}</h2>
{/* 用户详情 */}
</div>
);
}
// 错误1:在JSX中使用if语句
function WrongExample1() {
const isVisible = true;
return (
<div>
{/* 错误:if语句不能在JSX中直接使用 */}
{if (isVisible) {
return <p>可见内容</p>;
}}
{/* 正确:使用三元运算符或逻辑与 */}
{isVisible && <p>可见内容</p>}
</div>
);
}
// 错误2:逻辑与运算符渲染0
function WrongExample2() {
const items = []; // 空数组
const count = items.length; // count = 0
return (
<div>
{/* 错误:当count为0时,会渲染0 */}
{count && <p>有 {count} 个项目</p>}
{/* 正确:显式转换为布尔值 */}
{count > 0 && <p>有 {count} 个项目</p>}
{/* 正确:使用三元运算符 */}
{count ? <p>有 {count} 个项目</p> : null}
</div>
);
}
// 错误3:忘记处理所有条件分支
function WrongExample3({ status }) {
// 错误:没有处理所有可能的status值
if (status === 'loading') {
return <div>加载中...</div>;
}
if (status === 'success') {
return <div>成功</div>;
}
// 如果status是'error'或其他值,会返回undefined
// React会抛出错误
// 正确:添加默认返回
return <div>未知状态</div>;
}
// 错误4:条件渲染导致不必要的重新渲染
function WrongExample4() {
const [count, setCount] = useState(0);
const [showMessage, setShowMessage] = useState(false);
// 错误:每次渲染都会创建新函数
const renderMessage = () => {
if (showMessage) {
return <div>消息内容</div>;
}
return null;
};
return (
<div>
<button onClick={() => setCount(count + 1)}>
计数: {count}
</button>
<button onClick={() => setShowMessage(!showMessage)}>
切换消息
</button>
{/* 每次渲染都会调用renderMessage */}
{renderMessage()}
</div>
);
// 正确:直接在JSX中使用条件
// {showMessage && <div>消息内容</div>}
}
import { CSSTransition } from 'react-transition-group';
function AnimatedConditional() {
const [show, setShow] = useState(false);
return (
<div>
<button onClick={() => setShow(!show)}>
{show ? '隐藏' : '显示'}内容
</button>
<CSSTransition
in={show}
timeout={300}
classNames="fade"
unmountOnExit
>
<div className="conditional-content">
这个内容会带有动画效果显示和隐藏
</div>
</CSSTransition>
</div>
);
}
// CSS样式
// .fade-enter { opacity: 0; }
// .fade-enter-active { opacity: 1; transition: opacity 300ms; }
// .fade-exit { opacity: 1; }
// .fade-exit-active { opacity: 0; transition: opacity 300ms; }