SolidJS 条件渲染和列表渲染
本规则集定义了在 SolidJS 应用程序中实现条件渲染和列表渲染的最佳实践,旨在确保高效的 UI 更新和可读的代码结构。
1. 条件渲染
SolidJS 处理条件渲染的方式与 React 等其他库有所不同,它利用其细粒度响应式系统,只更新实际改变的部分。
1.1 使用 Show 组件
对于简单的条件渲染,可以使用 SolidJS 内置的 Show 组件。它接受一个 when 属性(一个信号或计算属性),当 when 为真时渲染其 children,否则渲染 fallback。
import { createSignal, Show } from 'solid-js';
function ConditionalDisplay() {
const [loggedIn, setLoggedIn] = createSignal(false);
return (
<div>
<Show
when={loggedIn()}
fallback={<button => setLoggedIn(true)}>Login</button>}
>
<p>Welcome, User!</p>
<button => setLoggedIn(false)}>Logout</button>
</Show>
</div>
);
}
1.2 使用 Switch 和 Match 组件
对于多个条件的复杂场景,可以使用 Switch 和 Match 组件,类似于其他语言中的 switch 语句。
import { createSignal, Switch, Match } from 'solid-js';
function MultiConditionalDisplay() {
const [status, setStatus] = createSignal('loading');
return (
<div>
<Switch fallback={<p>Unknown Status</p>}>
<Match when={status() === 'loading'}>
<p>Loading data...</p>
</Match>
<Match when={status() === 'success'}>
<p>Data loaded successfully!</p>
</Match>
<Match when={status() === 'error'}>
<p style={{ color: 'red' }}>Error loading data.</p>
</Match>
</Switch>
<button => setStatus('loading')}>Set Loading</button>
<button => setStatus('success')}>Set Success</button>
<button => setStatus('error')}>Set Error</button>
</div>
);
}
1.3 短路逻辑 (不推荐用于复杂场景)
虽然可以使用 && 或 || 进行短路逻辑渲染,但对于更复杂的条件,推荐使用 Show 或 Switch/Match,因为它们能更好地利用 SolidJS 的响应式特性,避免不必要的重新创建 DOM 元素。
// 简单场景可用,复杂场景不推荐
function SimpleConditional() {
const [isVisible, setIsVisible] = createSignal(true);
return (
<div>
{isVisible() && <p>This is visible.</p>}
<button => setIsVisible(v => !v)}>Toggle</button>
</div>
);
}
2. 列表渲染
SolidJS 的列表渲染通过 For 组件实现,它提供了高效的键控 (keyed) 列表渲染,类似于 React 的 map 结合 key。
2.1 使用 For 组件
For 组件接受一个 each 属性(一个数组信号或计算属性),并为数组中的每个项渲染其 children。key 属性是可选的,但强烈推荐提供一个稳定且唯一的 key,以优化列表更新性能。
import { createSignal, For } from 'solid-js';
function TodoList() {
const [todos, setTodos] = createSignal([
{ id: 1, text: 'Learn SolidJS', completed: false },
{ id: 2, text: 'Build an App', completed: false },
]);
const addTodo = () => {
const newTodo = { id: todos().length + 1, text: 'New Todo', completed: false };
setTodos([...todos(), newTodo]);
};
return (
<div>
<button Todo</button>
<ul>
<For each={todos()} fallback={<p>No todos yet!</p>}>
{(todo, i) => (
<li>
{todo.text} - {todo.completed ? 'Done' : 'Pending'}
</li>
)}
</For>
</ul>
</div>
);
}
2.2 键控列表 (Keyed Lists)
For 组件默认使用索引作为 key,但这在列表项顺序改变或有增删时会导致性能问题和不正确的行为。因此,始终为 For 组件提供一个稳定的、唯一的 key。
// 推荐使用唯一的 ID 作为 key
<For each={todos()} fallback={<p>No todos yet!</p>}>
{(todo) => <li key={todo.id}>{todo.text}</li>}
</For>
2.3 避免在 For 循环中创建信号
在 For 循环内部直接创建信号会导致性能问题,因为每次列表更新时都会重新创建信号。如果需要响应式地处理列表项的内部状态,应将列表项封装到独立的组件中,并在该组件内部管理其状态。
3. 最佳实践
- 优先使用内置组件: 对于条件渲染和列表渲染,优先使用 SolidJS 提供的
Show、Switch/Match和For组件。 - 提供唯一的
key: 在For组件中始终提供一个稳定的、唯一的key。 - 避免短路逻辑的滥用: 避免在复杂场景下使用
&&或||进行条件渲染。 - 封装列表项: 如果列表项有自己的内部状态或复杂逻辑,将其封装到独立的组件中。