条件渲染 #
一、条件渲染概述 #
1.1 Solid 的条件渲染方式 #
Solid 提供了多种条件渲染方式,最推荐使用内置的控制流组件。
text
┌─────────────────────────────────────────────────────────────┐
│ 条件渲染方式对比 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. Show 组件(推荐) │
│ └── 简单条件渲染 │
│ └── 支持 fallback │
│ │
│ 2. Switch/Match 组件 │
│ └── 多条件分支 │
│ └── 类似 switch-case │
│ │
│ 3. 三元表达式 │
│ └── 简单条件 │
│ └── JSX 内联使用 │
│ │
│ 4. 逻辑与 (&&) │
│ └── 条件显示 │
│ └── 注意 falsy 值 │
│ │
└─────────────────────────────────────────────────────────────┘
二、Show 组件 #
2.1 基本用法 #
jsx
import { Show } from 'solid-js';
function Example() {
const [loggedIn, setLoggedIn] = createSignal(false);
return (
<div>
<Show when={loggedIn()}>
<p>Welcome back!</p>
</Show>
</div>
);
}
2.2 带 fallback #
jsx
function Example() {
const [user, setUser] = createSignal(null);
return (
<Show
when={user()}
fallback={<p>Please log in</p>}
>
{(userData) => (
<div>
<h1>Hello, {userData().name}!</h1>
<p>Email: {userData().email}</p>
</div>
)}
</Show>
);
}
2.3 keyed 模式 #
jsx
function UserList() {
const [selectedId, setSelectedId] = createSignal(1);
const [users] = createResource(() => selectedId(), fetchUser);
return (
<div>
<Show when={users()} keyed>
{(user) => (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
)}
</Show>
</div>
);
}
2.4 嵌套 Show #
jsx
function Permissions() {
const [user, setUser] = createSignal(null);
const [isAdmin, setIsAdmin] = createSignal(false);
return (
<Show when={user()} fallback={<LoginButton />}>
<Show when={isAdmin()} fallback={<UserDashboard />}>
<AdminDashboard />
</Show>
</Show>
);
}
2.5 Show 的优势 #
jsx
// 使用 Show:DOM 元素被正确管理
<Show when={show()}>
<ExpensiveComponent />
</Show>
// 使用三元表达式:每次切换都会重新创建
{show() ? <ExpensiveComponent /> : null}
三、Switch/Match 组件 #
3.1 基本用法 #
jsx
import { Switch, Match } from 'solid-js';
function StatusMessage() {
const [status, setStatus] = createSignal('loading');
return (
<Switch>
<Match when={status() === 'loading'}>
<p>Loading...</p>
</Match>
<Match when={status() === 'success'}>
<p>Operation completed successfully!</p>
</Match>
<Match when={status() === 'error'}>
<p>An error occurred!</p>
</Match>
</Switch>
);
}
3.2 带 fallback #
jsx
function RouteHandler() {
const [route, setRoute] = createSignal('/home');
return (
<Switch fallback={<NotFound />}>
<Match when={route() === '/home'}>
<HomePage />
</Match>
<Match when={route() === '/about'}>
<AboutPage />
</Match>
<Match when={route() === '/contact'}>
<ContactPage />
</Match>
</Switch>
);
}
3.3 使用状态值 #
jsx
function UserRole() {
const [user, setUser] = createSignal({ role: 'admin' });
return (
<Switch fallback={<p>Unknown role</p>}>
<Match when={user().role === 'admin'}>
<AdminPanel />
</Match>
<Match when={user().role === 'editor'}>
<EditorPanel />
</Match>
<Match when={user().role === 'viewer'}>
<ViewerPanel />
</Match>
</Switch>
);
}
3.4 复杂条件 #
jsx
function PermissionGate() {
const [user, setUser] = createSignal(null);
const [permissions, setPermissions] = createSignal([]);
return (
<Switch>
<Match when={!user()}>
<LoginPrompt />
</Match>
<Match when={permissions().includes('admin')}>
<AdminControls />
</Match>
<Match when={permissions().includes('write')}>
<EditorControls />
</Match>
<Match when={permissions().includes('read')}>
<ReadOnlyView />
</Match>
</Switch>
);
}
四、三元表达式 #
4.1 基本用法 #
jsx
function Example() {
const [isLoggedIn, setIsLoggedIn] = createSignal(false);
return (
<div>
{isLoggedIn() ? <Dashboard /> : <LoginPage />}
</div>
);
}
4.2 内联使用 #
jsx
function Button() {
const [loading, setLoading] = createSignal(false);
return (
<button disabled={loading()}>
{loading() ? 'Loading...' : 'Submit'}
</button>
);
}
4.3 嵌套三元 #
jsx
// 不推荐:难以阅读
function BadExample() {
return (
<div>
{status() === 'loading' ? (
<Loading />
) : status() === 'error' ? (
<Error />
) : (
<Content />
)}
</div>
);
}
// 推荐:使用 Switch
function GoodExample() {
return (
<Switch>
<Match when={status() === 'loading'}><Loading /></Match>
<Match when={status() === 'error'}><Error /></Match>
<Match when={true}><Content /></Match>
</Switch>
);
}
五、逻辑与 (&&) #
5.1 基本用法 #
jsx
function Notifications() {
const [count, setCount] = createSignal(5);
return (
<div>
{count() > 0 && (
<span class="badge">{count()}</span>
)}
</div>
);
}
5.2 注意 falsy 值 #
jsx
// 问题:0 会被渲染
function BadExample() {
const [count, setCount] = createSignal(0);
return (
<div>
{count() && <span>{count()}</span>}
{/* 当 count 为 0 时,会显示 0 */}
</div>
);
}
// 解决方案:使用显式条件
function GoodExample() {
const [count, setCount] = createSignal(0);
return (
<div>
{count() > 0 && <span>{count()}</span>}
</div>
);
}
// 或者使用 Show
function BetterExample() {
const [count, setCount] = createSignal(0);
return (
<Show when={count() > 0}>
<span>{count()}</span>
</Show>
);
}
六、实际应用 #
6.1 加载状态 #
jsx
function DataFetcher({ url }) {
const [data] = createResource(() => url(), fetchData);
return (
<Switch>
<Match when={data.loading}>
<LoadingSpinner />
</Match>
<Match when={data.error}>
<ErrorMessage error={data.error} />
</Match>
<Match when={data()}>
{(result) => (
<DataDisplay data={result()} />
)}
</Match>
</Switch>
);
}
6.2 表单验证 #
jsx
function FormField({ label, error, ...props }) {
return (
<div class="form-field">
<label>{label}</label>
<input {...props} class={error() ? 'error' : ''} />
<Show when={error()}>
<span class="error-message">{error()}</span>
</Show>
</div>
);
}
6.3 权限控制 #
jsx
function ProtectedRoute({ permission, children }) {
const { hasPermission } = useAuth();
return (
<Show
when={hasPermission(permission)}
fallback={<AccessDenied />}
>
{children}
</Show>
);
}
// 使用
<ProtectedRoute permission="admin">
<AdminPanel />
</ProtectedRoute>
6.4 标签页切换 #
jsx
function Tabs({ tabs }) {
const [activeTab, setActiveTab] = createSignal(0);
return (
<div>
<div class="tab-header">
<For each={tabs}>
{(tab, index) => (
<button
class={activeTab() === index() ? 'active' : ''}
onClick={() => setActiveTab(index())}
>
{tab.label}
</button>
)}
</For>
</div>
<div class="tab-content">
<Switch>
<For each={tabs}>
{(tab, index) => (
<Match when={activeTab() === index()}>
{tab.content}
</Match>
)}
</For>
</Switch>
</div>
</div>
);
}
6.5 空状态处理 #
jsx
function TodoList() {
const [todos, setTodos] = createSignal([]);
return (
<div>
<Show
when={todos().length > 0}
fallback={
<div class="empty-state">
<p>No todos yet. Add one to get started!</p>
</div>
}
>
<ul>
<For each={todos()}>
{(todo) => <TodoItem todo={todo} />}
</For>
</ul>
</Show>
</div>
);
}
七、性能考虑 #
7.1 Show vs 三元表达式 #
jsx
// Show:保持 DOM 状态
<Show when={show()}>
<ExpensiveComponent />
</Show>
// 三元:每次切换重新创建
{show() ? <ExpensiveComponent /> : null}
7.2 条件渲染的位置 #
jsx
// 推荐:在组件外部判断
function Parent() {
const [show, setShow] = createSignal(false);
return (
<Show when={show()}>
<ExpensiveComponent />
</Show>
);
}
// 不推荐:在组件内部判断
function ExpensiveComponent() {
const [show, setShow] = createSignal(false);
if (!show()) return null; // 组件仍然会被创建
return <div>...</div>;
}
八、最佳实践 #
8.1 选择合适的条件渲染方式 #
| 场景 | 推荐方式 |
|---|---|
| 简单条件 | Show |
| 多条件分支 | Switch/Match |
| 内联小内容 | 三元表达式 |
| 条件显示 | Show 或 && |
8.2 代码组织 #
jsx
// 推荐:条件渲染逻辑清晰
function UserStatus() {
const { user, loading, error } = useAuth();
return (
<div class="user-status">
<Switch>
<Match when={loading()}>
<LoadingIndicator />
</Match>
<Match when={error()}>
<ErrorDisplay error={error()} />
</Match>
<Match when={user()}>
{(u) => <UserProfile user={u()} />}
</Match>
</Switch>
</div>
);
}
九、总结 #
9.1 条件渲染 API #
| API | 说明 |
|---|---|
Show |
条件渲染组件 |
Switch |
多条件容器 |
Match |
条件分支 |
when |
条件表达式 |
fallback |
默认内容 |
9.2 最佳实践 #
- 优先使用 Show:简单条件渲染
- 使用 Switch/Match:多条件分支
- 避免嵌套三元:使用 Switch 替代
- 注意 falsy 值:使用显式条件
- 考虑性能:Show 保持 DOM 状态
最后更新:2026-03-28