Idioms and Patterns
Element's reactive system and template-based approach enable powerful patterns for building modern Web applications. This guide covers common idioms, best practices, and advanced techniques for getting the most out of Element.
Reactive Patterns
Understanding how to effectively use Element's reactive system is key to building maintainable and performant applications.
Derived State
Derived state is computed from other signals and automatically updates when dependencies change. This pattern is fundamental to creating clean, declarative UIs.
// Computed with conditional dependencies
const [withEmail, setWithEmail] = createSignal(false);
const [user, setUser] = createSignal({
name: "John Doe",
email: "john.doe@pm.me",
});
const author = createComputed(() => {
if (withEmail()) {
return `${user().name} <${user().email}>`;
}
return user().name;
});
// Computed with array operations
const [tasks, setTasks] = createSignal([
{ id: "I", text: "Inhale", completed: true },
{ id: "E", text: "Exhale", completed: true },
{ id: "R", text: "Repeat", completed: false },
]);
const completedCount = createComputed(() => {
return tasks().filter((task) => task.completed).length;
});
const uncompletedCount = createComputed(() => {
return tasks().length - completedCount();
});
Conditional Effects
const [isAuthenticated, setIsAuthenticated] = createSignal(false);
const [user, setUser] = createSignal<User | null>(null);
createEffect(() => {
if (isAuthenticated()) {
fetchUserData().then((data) => {
setUser(data);
});
return () => {
setUser(null);
};
}
});
Resource Loading Pattern
A common pattern for managing asynchronous resources with loading states and error handling.
function createResource<T>(fetcher: () => Promise<T>) {
const [data, setData] = createSignal<T | null>(null);
const [loading, setLoading] = createSignal(false);
const [error, setError] = createSignal<Error | null>(null);
const load = async () => {
setLoading(true);
setError(null);
try {
const result = await fetcher();
setData(result);
} catch (err) {
setError(err instanceof Error ? err : new Error(String(err)));
} finally {
setLoading(false);
}
};
load();
return {
data,
loading,
error,
reload: () => {
setData(null);
load();
},
};
}
Nested Batching
const [a, setA] = createSignal(0);
const [b, setB] = createSignal(0);
const [c, setC] = createSignal(0);
createEffect(() => {
console.log("Value:", a() * b() * c());
});
createBatch(() => {
setA(1);
// Nested batches are supported
createBatch(() => {
setB(2);
setC(3);
});
});
Advanced Template Features
Element's template system provides sophisticated features for building complex UIs while maintaining reactivity and performance.
Nested Components
Components can be nested and composed to create reusable UI elements.
function Header() {
return html`<header><h1>Hello World!</h1></header>`;
}
function Footer() {
return html`<footer>All Rights Reserved ©</footer>`;
}
function App() {
return html`
<div>
${Header()}
<main>Lorem ipsum dolor sit amet...</main>
${Footer()}
</div>
`;
}
document.body.appendChild(App());
Last updated