Preact Signals: Revolutionizing State Management in Web Applications
State management remains one of the most challenging aspects of modern web development. Preact Signals emerges as an elegant and efficient solution, offering a simple API with exceptional performance characteristics.
What are Signals?
Signals are reactive containers that hold values and automatically notify dependent components when those values change. Unlike traditional state management solutions, Signals are incredibly lightweight and require minimal boilerplate code.
Why Choose Signals?
Superior Performance
Granular updates that minimize unnecessary re-renders
Minimal overhead compared to traditional solutions
Reduced need for memo or useMemo hooks
Developer-Friendly API
Clear, straightforward syntax
Gentle learning curve
Seamless integration with Preact components
Minimal Bundle Size
Only ~1KB gzipped
Perfect for performance-critical applications
Practical Examples
Basic Example: Counter
import { signal } from "@preact/signals";
import { render } from "preact";
const count = signal(0);
function Counter() {
return (
<div>
<p>Count: {count.value}</p>
<button onClick={() => count.value++}>Increment</button>
</div>
);
}
Advanced Example: Todo List
import { signal, computed } from "@preact/signals";
const todos = signal([]);
const filter = signal('all');
// Computed signal for filtering todos
const filteredTodos = computed(() => {
switch (filter.value) {
case 'active':
return todos.value.filter(todo => !todo.completed);
case 'completed':
return todos.value.filter(todo => todo.completed);
default:
return todos.value;
}
});
function TodoList() {
const addTodo = (text) => {
todos.value = [...todos.value, { id: Date.now(), text, completed: false }];
};
const toggleTodo = (id) => {
todos.value = todos.value.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
);
};
return (
<div>
<input
onKeyPress={e => e.key === 'Enter' && addTodo(e.target.value)}
placeholder="New todo"
/>
<div>
{filteredTodos.value.map(todo => (
<div key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span>{todo.text}</span>
</div>
))}
</div>
<div>
<button onClick={() => filter.value = 'all'}>All</button>
<button onClick={() => filter.value = 'active'}>Active</button>
<button onClick={() => filter.value = 'completed'}>Completed</button>
</div>
</div>
);
}
Best Practices
1 - Leverage computed
for Derived Values
const count = signal(0);
const doubled = computed(() => count.value * 2);
2 - Avoid Direct Mutations
// ❌ Wrong
todos.value.push(newTodo);
// ✅ Correct
todos.value = [...todos.value, newTodo];
Keep Signals at the Highest Possible Level
Define signals outside components for global state
Use signals inside components only for local state
Signal Composition
const user = signal({ name: 'John', age: 30 });
const formattedUser = computed(() =>
`${user.value.name} (${user.value.age})`
);
Performance Tips
Granular Signals
- Split large state objects into multiple signals for better performance
// Instead of
const userState = signal({ name: '', email: '', preferences: {} });
// Use
const userName = signal('');
const userEmail = signal('');
const userPreferences = signal({});
Batch Updates
- Use batch functions to update together very fast a lot of signals
function updateUser() {
batch(() => {
userName.value = 'Jane';
userEmail.value = 'jane@example.com';
});
}
Migrating from useState
jsxCopy// Before
const [count, setCount] = useState(0);
// After
const count = signal(0);
// Use count.value to read
// Use count.value = newValue to write
Conclusion
Preact Signals offers a modern and efficient approach to state management. Its simplicity, performance benefits, and ease of use make it an excellent choice for projects of any scale.
The combination of minimal boilerplate, intuitive API, and exceptional performance positions Signals as a compelling alternative to traditional state management solutions. Whether you're building a small application or a complex system, Preact Signals provides the tools needed for effective state management while maintaining optimal performance.
Next time you start a new project, consider giving Preact Signals a try – you might find it's the state management solution you've been looking for.