@pulselang/react
v3.1.0
Published
React hooks for Pulse language primitives
Maintainers
Readme
@pulselang/react
React hooks for Pulse language primitives. Brings Pulse's fine-grained reactivity to React applications.
Installation
npm install @pulselang/react pulselang reactHooks
useSignal(initialValue)
Creates a reactive signal that triggers React re-renders on updates.
import { useSignal } from '@pulselang/react';
function Counter() {
const [count, setCount] = useSignal(0);
return (
<button onClick={() => setCount(count() + 1)}>
Count: {count()}
</button>
);
}useComputed(fn)
Creates a derived computed value that automatically tracks dependencies.
import { useSignal, useComputed } from '@pulselang/react';
function Counter() {
const [count, setCount] = useSignal(0);
const doubled = useComputed(() => count() * 2);
return (
<div>
<p>Count: {count()}</p>
<p>Doubled: {doubled()}</p>
<button onClick={() => setCount(count() + 1)}>Increment</button>
</div>
);
}useEffectPulse(fn)
Runs an effect when Pulse dependencies change. Uses fine-grained tracking.
import { useSignal, useEffectPulse } from '@pulselang/react';
function Logger() {
const [count, setCount] = useSignal(0);
useEffectPulse(() => {
console.log('Count changed to:', count());
});
return <button onClick={() => setCount(count() + 1)}>Increment</button>;
}usePulseValue(getter)
Subscribes to any Pulse signal or computed and returns the current value.
import { usePulseValue } from '@pulselang/react';
import { count } from './counter.pulse';
function Display() {
const currentCount = usePulseValue(count);
return <div>Count: {currentCount}</div>;
}useChannel(bufferSize)
Creates a Pulse channel for concurrent communication.
import { useChannel } from '@pulselang/react';
function Chat() {
const messages = useChannel(100);
const sendMessage = async (text) => {
await messages.send(text);
};
return <div>...</div>;
}createPulseContext(initialValue)
Creates a shared signal that works across components.
import { createPulseContext } from '@pulselang/react';
const [ThemeProvider, useTheme] = createPulseContext('light');
function App() {
return (
<ThemeProvider>
<Header />
<Main />
</ThemeProvider>
);
}
function Header() {
const [theme, setTheme] = useTheme();
return (
<button onClick={() => setTheme(theme() === 'light' ? 'dark' : 'light')}>
Toggle theme (current: {theme()})
</button>
);
}Using with Pulse files
Combine with vite-plugin-pulse to import Pulse files directly:
// counter.pulse
import { signal } from 'pulselang/runtime/reactivity'
export const [count, setCount] = signal(0)
export fn increment() {
setCount(count() + 1)
}
export fn decrement() {
setCount(count() - 1)
}// Counter.jsx
import { usePulseValue } from '@pulselang/react';
import { count, increment, decrement } from './counter.pulse';
export function Counter() {
const currentCount = usePulseValue(count);
return (
<div>
<button onClick={decrement}>-</button>
<span>{currentCount}</span>
<button onClick={increment}>+</button>
</div>
);
}Performance
Pulse uses fine-grained reactivity, meaning only components that read specific signals will re-render when those signals change. This is more efficient than React's default reconciliation.
However, since we're bridging two reactive systems (Pulse and React), there's a small overhead. For best performance, prefer using Pulse's reactivity directly or use usePulseValue to subscribe to signals defined in .pulse files.
