A lightweight React library that brings the power of Preact Signals to React applications with enhanced features and an intuitive API.
bash
npm install react-set-signal
`
or with pnpm:
`bash
pnpm add react-set-signal
`
Quick Start
`javascript
import { useReactive } from 'react-set-signal';
function Counter() {
const [count, setCount] = useReactive(0);
return (
Count: {count}
);
}
`
API Reference
$3
A React hook that creates a reactive state with Preact Signals under the hood. Similar to useState, but with enhanced features.
Parameters:
- initialState - The initial value of the state
Returns:
- [state, setState] - A tuple containing the current state and a setter function
Example:
`javascript
import { useReactive } from 'react-set-signal';
function TodoList() {
const [todos, setTodos] = useReactive([
{ id: 1, text: 'Learn React', completed: false }
]);
const toggleTodo = (id) => {
// Immer-style draft mutation
setTodos((draft) => {
const todo = draft.find(t => t.id === id);
if (todo) todo.completed = !todo.completed;
});
};
const addTodo = (text) => {
// Direct value update
setTodos((draft) => {
draft.push({ id: Date.now(), text, completed: false });
});
};
return (
{todos.map(todo => (
toggleTodo(todo.id)}>
{todo.text}
))}
);
}
`
$3
A React hook that subscribes to an existing Preact Signal and returns its current value. This is useful for sharing state across components.
Parameters:
- $signal - A Preact Signal instance
Returns:
- state - The current value of the signal
Example:
`javascript
import { createSignal, useReactiveSignal } from 'react-set-signal';
// Create a global signal
const $counter = createSignal(0);
function DisplayCounter() {
const count = useReactiveSignal($counter);
return Count: {count}
;
}
function IncrementButton() {
return (
);
}
function App() {
return (
<>
>
);
}
`
$3
Creates a new Preact Signal with an enhanced API that includes an Immer-style setter method.
Parameters:
- initialValue - The initial value of the signal
Returns:
- $signal - A Preact Signal with an additional .set() method
Example:
`javascript
import { createSignal } from 'react-set-signal';
const $user = createSignal({
name: 'John',
age: 30,
address: { city: 'New York' }
});
// Immer-style mutation
$user.set((draft) => {
draft.age = 31;
draft.address.city = 'Los Angeles';
});
// Or direct value update
$user.set({ name: 'Jane', age: 25, address: { city: 'Chicago' } });
// Or function returning new value
$user.set((current) => ({ ...current, age: current.age + 1 }));
`
$3
The library also re-exports core Preact Signals functionality:
`javascript
import { signal, effect, computed } from 'react-set-signal';
`
- signal(initialValue) - Create a standard Preact Signal
- effect(fn) - Create an effect that runs when signals change
- computed(fn) - Create a derived signal that automatically updates when its dependencies change
Advanced Usage
$3
Create global signals that can be accessed across your application:
`javascript
// store.js
import { createSignal } from 'react-set-signal';
export const $theme = createSignal('light');
export const $user = createSignal(null);
export const $settings = createSignal({
notifications: true,
sound: false
});
`
`javascript
// ThemeToggle.jsx
import { useReactiveSignal } from 'react-set-signal';
import { $theme } from './store';
function ThemeToggle() {
const theme = useReactiveSignal($theme);
return (
);
}
`
$3
The setter function supports Immer-style draft mutations, making complex nested updates simple:
`javascript
const [state, setState] = useReactive({
users: [
{ id: 1, name: 'Alice', posts: [] },
{ id: 2, name: 'Bob', posts: [] }
],
selectedUserId: null
});
// Complex nested update
setState((draft) => {
const user = draft.users.find(u => u.id === 1);
user.posts.push({ id: Date.now(), title: 'New Post' });
draft.selectedUserId = 1;
});
`
$3
Use Preact's effect for side effects:
Example with effect:
`javascript
import { createSignal, effect } from 'react-set-signal';
const $count = createSignal(0);
// Run side effect when signal changes
effect(() => {
console.log('Count changed:', $count.value);
document.title = Count: ${$count.value};
});
`
Use Preact's computed for computed values:
Example with computed:
`javascript
import { createSignal, computed, useReactiveSignal } from 'react-set-signal';
const $firstName = createSignal('John');
const $lastName = createSignal('Doe');
// Computed signal: automatically updates when firstName or lastName changes
const $fullName = computed(() => ${$firstName.value} ${$lastName.value});
function Profile() {
const fullName = useReactiveSignal($fullName);
return {fullName}
;
}
// Update signals
$firstName.set('Jane');
// $fullName automatically recomputes to "Jane Doe"
`
How It Works
react-set-signal uses React's useSyncExternalStore` hook to subscribe to Preact Signals, ensuring compatibility with React 18+ concurrent features. State updates are handled through Mutative, providing Immer-style immutable updates with better performance.