npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

fluidstate-preact

v1.0.0

Published

Library for using fine-grained reactivity state management library fluidstate in Preact

Readme

fluidstate-preact

View interactive documentation on the official website.:

fluidstate-preact provides Preact bindings for the fluidstate fine-grained reactivity library. It allows you to build highly performant Preact applications where components update automatically and efficiently in response to state changes, without manual subscriptions or monolithic state updates.

A Library with Two Roles

fluidstate-preact is designed to serve two distinct but complementary purposes:

  1. Standalone Reactive Layer: It offers a reactive layer for fluidstate built on top of @preact/signals-core. This part of the library can be used independently of Preact, enabling you to leverage the performance of Preact Signals in any fluidstate-powered JavaScript application.

  2. Preact Bindings: It provides a rich set of tools—hooks, Higher-Order Components (HOCs), and signal-based utilities—to seamlessly integrate fluidstate's reactive state into your Preact components, offering multiple patterns for different use cases.

Features

  • Fine-grained reactivity: Components re-render only when the specific data they use changes.
  • Multiple Integration Patterns: Choose from the useReactive hook, withReactive HOC, or the hyper-performant useSignals hook.
  • Standalone Reactive Layer: A fluidstate reactive layer powered by @preact/signals-core that can be used in any environment, even without Preact.
  • createReactiveSetup: A powerful pattern for creating encapsulated, reusable, and testable state management modules with Providers and consumer hooks/HOCs.
  • Seamless integration: Works with the entire fluidstate ecosystem, regardless of the underlying reactive layer.

Installation

You will need fluidstate and fluidstate-preact. Depending on which features you use, you may also need to install preact, @preact/signals-core, and @preact/signals as peer dependencies.

# Core library
npm install fluidstate fluidstate-preact

# or
yarn add fluidstate fluidstate-preact

Optional Peer Dependencies:

  • To use the Preact bindings (useReactive, withReactive, createReactiveSetup): install preact.
  • To use the useSignals hook: install preact and @preact/signals.
  • To use the standalone reactive layer: install @preact/signals-core.

Example: To use everything, you would install:

npm install preact @preact/signals @preact/signals-core
# or
yarn add preact @preact/signals @preact/signals-core

Part 1: Standalone Reactive Layer (via @preact/signals)

fluidstate-preact includes a reactive layer that bridges fluidstate with @preact/signals-core. This allows you to use fluidstate's ergonomic API while leveraging the highly efficient Preact Signals engine under the hood.

This layer can be used in any project, even one that doesn't use Preact for its UI, making it a powerful choice for any fluidstate-based application.

Setup

To enable fluidstate, you must provide it with a reactive layer. This is a one-time setup at your application's entry point.

// file: main.ts
import {
	provideReactiveLayer,
	createReactive,
	createReaction,
	runAction,
} from "fluidstate";
// Note the import path for the reactive layer
import { getReactiveLayer } from "fluidstate-preact/reactive-layer";

// 1. Get the reactive layer from fluidstate-preact
const reactiveLayer = getReactiveLayer();

// 2. Provide it to fluidstate
provideReactiveLayer(reactiveLayer);

// 3. You can now use the fluidstate API throughout your application
const counter = createReactive({ value: 0 });

createReaction(() => {
	console.log(`Counter value: ${counter.value}`);
});
// LOGS: Counter value: 0

runAction(() => {
	counter.value++;
});
// LOGS: Counter value: 1

After this setup, you can use the fluidstate package for all your state management tasks. For more details on createReactive, createReaction, and other features, please refer to the main fluidstate documentation.

Part 2: Preact Bindings

This part of the library is focused on integrating your fluidstate reactive state into Preact components.

One-Time Setup

Before using any Preact bindings, you must configure fluidstate with a reactive layer, as shown in Part 1. You can use any fluidstate reactive layer (e.g., fluidstate-alien, fluidstate-mobx or fluidstate-preact/reactive-layer). The Preact bindings are agnostic to the underlying engine.

Three Ways to Consume State

fluidstate-preact offers three primary ways to make your components reactive, each with different trade-offs.

1. useReactive Hook

The useReactive hook is a flexible way to consume reactive state. You provide a function that reads from your state, and the hook ensures your component re-renders whenever any of the accessed state properties change.

Example Store:

// file: counter-store.ts
import { createReactive } from "fluidstate";

export type CounterStore = {
	count: number;
	increment: () => void;
	decrement: () => void;
};

export const counterStore = createReactive<CounterStore>({
	count: 0,
	increment() {
		counterStore.count++;
	},
	decrement() {
		counterStore.count--;
	},
});

Component using useReactive:

// file: counter.tsx
import { useReactive } from "fluidstate-preact";
import { counterStore } from "./counter-store";

export const Counter = () => {
	// The component will re-render only when `counterStore.count` changes.
	const count = useReactive(() => counterStore.count);

	return (
		<div>
			<h1>Counter: {count}</h1>
			<button onClick={counterStore.increment}>Increment</button>
			<button onClick={counterStore.decrement}>Decrement</button>
		</div>
	);
};

2. withReactive HOC

The withReactive HOC provides an alternative, wrapping your component to make it automatically re-render when any reactive state it accesses changes.

// file: counter-hoc.tsx
import { withReactive } from "fluidstate-preact";
import { counterStore } from "./counter-store";

export const CounterComponent = withReactive(() => {
	return (
		<div>
			<h1>Counter: {counterStore.count}</h1>
			<button onClick={counterStore.increment}>Increment</button>
			<button onClick={counterStore.decrement}>Decrement</button>
		</div>
	);
});

3. useSignals Hook

The useSignals hook is the most performant option. It bridges fluidstate state with @preact/signals, allowing you to update parts of your UI without re-rendering the entire component. This requires @preact/signals to be installed.

You can import useSignals from fluidstate-preact/signals.

// file: counter-signals.tsx
import { useSignals } from "fluidstate-preact/signals";
import { counterStore } from "./counter-store";

export const Counter = () => {
	// `get` is a function that creates a Preact signal for a given piece of state.
	const get = useSignals();

	return (
		<div>
			{/* The component itself only renders once. Only the text nodes update. */}
			<h1>Counter: {get(() => counterStore.count)}</h1>
			<button onClick={counterStore.increment}>Increment</button>
			<button onClick={counterStore.decrement}>Decrement</button>
		</div>
	);
};

Recommended Usage: createReactiveSetup

For larger applications, createReactiveSetup helps create encapsulated, testable, and reusable state modules. It generates a Provider, consumer hooks/HOCs, and a Context object for a specific slice of state.

Any reactions (e.g., for side effects) returned in a reactions array will be automatically cleaned up when the Provider unmounts.

Example: User Profile Module

1. Create the reactive setup

// file: user-profile-setup.ts
import {
	createReactive,
	Reaction,
	createReaction,
	cloneInert,
} from "fluidstate";
import { createReactiveSetup } from "fluidstate-preact";

export type UserProfileSetupProps = { initialName: string };
export type UserProfileData = { name: string; email: null | string };
export type UserProfileActions = {
	updateName: (newName: string) => void;
	setEmail: (email: string) => void;
};
export type UserProfileState = {
	data: UserProfileData;
	actions: UserProfileActions;
	reactions: Reaction[];
};

// Generate and rename the setup utilities for clarity.
export const {
	ReactiveProvider: UserProfileProvider,
	useReactiveState: useUserProfileState,
	withReactiveState: withUserProfileState,
	MockProvider: MockUserProfileProvider,
	StateContext: UserProfileContext, // Export the context for use with `useSignals`
} = createReactiveSetup((props: UserProfileSetupProps): UserProfileState => {
	const data = createReactive<UserProfileData>({
		name: props.initialName,
		email: null,
	});
	const actions = createReactive<UserProfileActions>({
		updateName(newName: string) {
			data.name = newName;
		},
		setEmail(email: string) {
			data.email = email;
		},
	});
	const syncProfile = createReaction(() => {
		fetch(`api/syncProfile`, {
			method: "POST",
			body: JSON.stringify(cloneInert(data)),
		});
	});
	return { data, actions, reactions: [syncProfile] };
});

2. Provide the state

// file: app.tsx
import { UserProfileProvider } from "./user-profile-setup";
import { UserProfileEditor } from "./user-profile-editor";
import { UserProfileDisplay } from "./user-profile-display";

export const App = () => (
	<UserProfileProvider setupProps={{ initialName: "John Doe" }}>
		<div>
			<h1>User Management</h1>
			<UserProfileEditor />
			<hr />
			<UserProfileDisplay />
		</div>
	</UserProfileProvider>
);

3. Consume the state

You can now consume state using the hook, HOC, or useSignals.

Using the useReactiveState hook:

// file: user-profile-editor.tsx
import { useUserProfileState } from "./user-profile-setup";

export const UserProfileEditor = () => {
	const { name, email, updateName, setEmail } = useUserProfileState(
		(state) => ({
			name: state.data.name,
			email: state.data.email,
			updateName: state.actions.updateName,
			setEmail: state.actions.setEmail,
		})
	);
	// ... component logic
};

Using useSignals for maximum performance:

// file: user-profile-display.tsx
import { useSignals } from "fluidstate-preact/signals";
import { UserProfileContext } from "./user-profile-setup";

export const UserProfileDisplay = () => {
	// Pass the context to `useSignals` to connect to the provider state.
	const get = useSignals(UserProfileContext);
	return (
		<div>
			<h2>Current Profile</h2>
			<p>
				<strong>Name:</strong> {get((state) => state.data.name)}
			</p>
			<p>
				<strong>Email:</strong> {get((state) => state.data.email ?? "Not set")}
			</p>
		</div>
	);
};

API Reference

useReactive<T>(getState: () => T, dependencyArray?: ReadonlyArray<unknown>): T

A Preact hook that subscribes a component to reactive state changes, causing a re-render when dependencies change.

withReactive<P>(Component: FunctionComponent<P>): FunctionComponent<P>

A HOC that makes a functional component reactive. It will re-render whenever any reactive state it accesses changes.

useSignals<CV>(Context?: Context<CV>): (fn: (value: CV) => T) => Signal<T>

A hook that returns a function to create Preact signals from fluidstate data.

  • Context: Optional. A Preact Context object (like one from createReactiveSetup) to source the state from. If omitted, it works with the state passed from the component.
  • The returned function get(fn) takes a selector and returns a memoized @preact/signal signal for the selected value.

createReactiveSetup<SetupProps, State>(createState)

A factory that creates a set of utilities for encapsulated state management.

It returns a ReactiveSetup object with:

  • ReactiveProvider: A Provider component that accepts setupProps.
  • useReactiveState: A hook to consume the state.
  • withReactiveState: A HOC to inject the state via a state prop.
  • StateContext: The Preact Context object used by the Provider. Pass this to useSignals to connect to the provided state.
  • MockProvider: A provider for testing that accepts a value prop with mock state.
  • createState: The original createState function, which can be useful for testing the state logic itself.

Package Entry Points

To keep the library modular and dependencies optional, features are exposed via different entry points:

  • fluidstate-preact: Core Preact bindings.

    • useReactive
    • withReactive
    • createReactiveSetup
  • fluidstate-preact/signals: The useSignals hook that uses @preact/signals.

    • useSignals
  • fluidstate-preact/reactive-layer: The standalone reactive layer backed by @preact/signals-core.

    • getReactiveLayer