Unlocking Seamless State Management in Preact with @preact/signals-react

Shehzad Ahmed
5 min readNov 10, 2023

--

Preact, renowned for its efficiency and lightweight nature, has continually revolutionized the landscape of frontend development. One area that remains pivotal in creating robust applications is state management. Enter @preact/signals-react, a powerful library designed to enhance state management within Preact applications but we will implement it in react cause that’s the goal.

Introduction to @preact/signals-react

@preact/signals-react simplifies state management by providing a comprehensive yet intuitive approach. At its core, the library harnesses the concept of signals – a structured and efficient way to manage state changes and propagate updates across components.

Key Features

  1. Signal-driven Architecture: Signals, as the backbone of this library, provide a clear pathway for handling state changes. They facilitate a unidirectional flow, enabling components to respond to changes efficiently.
  2. Efficient Re-renders: With a focus on performance, @preact/signals-react optimizes re-renders, ensuring that only the necessary components update when the state changes. This approach significantly improves the application's speed and responsiveness.

Why Choose @preact/signals-react?

Performance: In high-demand applications, performance is key. The signal-driven approach ensures optimal rendering, minimizing unnecessary updates and enhancing overall speed.

the screenshot below shows a DevTools Profiler trace for the same app measured twice, and once using hooks as the state primitive and a second time using signals. — [this image belongs to preact signals blog]

the screenshot below shows a DevTools Profiler trace for the same app measured twice, and once using hooks as the state primitive and a second time using signals. — this image belongs to preact signals blog

Simplicity: Managing complex state becomes simpler with the clear and structured methodology provided by signals. This clarity accelerates development and maintenance.

the screenshot below shows a state chaos that is caused by traditional state. — [this image belongs to preact signals blog]

the screenshot below shows a chaos that is caused by react context— [this image belongs to preact signals blog]

the screenshot below shows how signals solve the issues mentioned above. — [this image belongs to preact signals blog]

Getting Started

Implementing @preact/signals-react within your project is straightforward. By leveraging its intuitive API, developers can create and manage signals effectively. With clear documentation and examples, the library fosters a smooth onboarding experience for both seasoned and novice developers.

Here’s an example of how you might use @preact/signals-react for managing state in a React application:

Setting up Signals in a React Component

Let’s create a simple counter component to demonstrate the usage of @preact/signals-react.

For example we have an App component that have Sider, Header and Todos Component rendered in its body like this

import Header from "./Header";
import Sider from "./Sider";
import Todos from "./Todos";

function App() {
return (
<div>
<Header />
<Sider />
<div className="main-content">
<Todos />
</div>
</div>
);
}

export default App;

Here is a Todos.jsx file with add todo and mark as completed functionality

import React from "react";
import { signal, effect } from "@preact/signals-react";

const generateUniqueId = () => {
return Math.random().toString(36).substr(2, 9);
};

const getData = () => {
const value = localStorage.getItem("todos");
if (value === null) return [];
return JSON.parse(value);
};

export const todos = signal(getData());
const inputValue = signal("");

effect(() => {
localStorage.setItem("todos", JSON.stringify(todos.value));
});

const Todos = () => {

console.log("Todos rerenderd")
const addTodo = (e) => {
if (inputValue.value === "") return;
e.preventDefault();
todos.value = [
...todos.value,
{ id: generateUniqueId(), name: inputValue.value, isCompleted: false },
];
inputValue.value = "";
};

const onTodoChange = (e, todo) => {
const isCompleted = e.target.checked;
todos.value = todos.value.map((t) => {
if (t.id === todo.id) {
return { ...t, isCompleted };
}
return t;
});
};
return (
<div>
<div className="max-w-500 flex-center gap-5">
<div>
<label className="label">
<span className="label-text">Enter Todo</span>
</label>
<input
className="input"
type="text"
value={inputValue.value}
onChange={(e) => (inputValue.value = e.target.value)}
/>
</div>
<input
disabled={!inputValue.value}
type="button"
value={"Save"}
className="submit-btn"
onClick={addTodo}
/>
</div>
<h2>Todos</h2>
{todos.value.map((todo) => (
<div key={todo.id} className="flex-center">
<input
type="checkbox"
checked={todo.isCompleted}
onChange={(e) => onTodoChange(e, todo)}
/>
<p>{todo.name}</p>
</div>
))}
</div>
);
};

export default Todos;

Now here is a Header.jsx file that shows completed todos count in its body

import React from "react";
import {todos} from "./Todos.jsx"
import {computed} from "@preact/signals-react"

const completedTodos = computed(() => todos.value.filter(todo => todo.isCompleted))

const Header = () => {
console.log("Header rerendered")
return (
<header className="header">
<div className="flex-between-center">
<div className="logo">Logo</div>
<div className="completed-todos">Completed Todos: {completedTodos.value.length}</div>
</div>
</header>
);
};

export default Header

In the case mentioned above, if we use any other state management we would have to manage our state in the App component which would cause rerender across all App component’s children. which means even if Sider.jsx doesn't use todos state, it would still rerender. But with signals, we can simply export todos from Todos.jsx and import them anywhere in the app and that completely insane

Conclusion

State management in frontend development is a crucial aspect that directly influences an application’s performance and maintainability. @preact/signals-react emerges as a valuable addition to the state management tools, offering a clear and efficient solution for state management, emphasizing performance without compromising on simplicity.

By harnessing the power of signals, this library sets a new standard for managing state within Preact or React applications, unlocking a more streamlined and performant development experience.

Checkout above written code on my Github: React With Signals

Read more about signals: Introducing Signals by Preact

Get Started: Explore @preact/signals-react on npm

Signals GitHub Repository: View @preact/signals-react on GitHub

Find me on your favorite platform

  • Github — Follow me on GitHub for further useful code snippets and open source repos.
  • LinkedIn Profile — Connect with me on LinkedIn for further discussions and updates.
  • Twitter (X) — Connect with me on Twitter (X) for useless tech tweets.

--

--

No responses yet