You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

fluidstate-react

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fluidstate-react

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

1.0.2
latest
Source
npmnpm
Version published
Weekly downloads
15
Maintainers
1
Weekly downloads
 
Created
Source

fluidstate-react

View interactive documentation on the official website.

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

This library offers hooks and Higher-Order Components (HOCs) to seamlessly integrate fluidstate's reactive state into your React components.

Features

  • Fine-grained reactivity: Components re-render only when the specific data they use changes.
  • useReactive hook: A simple and powerful hook to create reactive views from your state.
  • withReactive HOC: A Higher-Order Component to make any functional component reactive.
  • 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.

Installation

You'll need react, fluidstate, a fluidstate reactive layer like fluidstate-mobx, and fluidstate-react.

npm install react fluidstate fluidstate-mobx fluidstate-react
# or
yarn add react fluidstate fluidstate-mobx fluidstate-react

Getting Started: One-Time Setup

fluidstate is designed as a layer on top of a core reactive engine. Before using fluidstate or fluidstate-react, you must provide this reactive layer. This is typically done once at the entry point of your application.

Here's how to set it up using fluidstate-mobx:

import { createRoot } from "react-dom/client";
import { provideReactiveLayer } from "fluidstate";
import { getReactiveLayer } from "fluidstate-mobx";
import { App } from "./app";

// 1. Get the reactive layer from the provider (e.g., fluidstate-mobx)
const reactiveLayer = getReactiveLayer();

// 2. Provide it to fluidstate. This enables all fluidstate features.
provideReactiveLayer(reactiveLayer);

// 3. Render your application
const root = createRoot(document.getElementById("app")!);
root.render(<App />);

With this setup complete, you can now use fluidstate-react's APIs in your components.

Core Usage

The two primary ways to make your components reactive are the useReactive hook and the withReactive HOC.

useReactive Hook

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

Here's an example of a simple counter:

import { createReactive } from "fluidstate";

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

// Create a reactive store.
// For more details on `createReactive`, see the fluidstate documentation.
export const counterStore = createReactive<CounterStore>({
	count: 0,
	increment() {
		counterStore.count++;
	},
	decrement() {
		counterStore.count--;
	},
});
import { useReactive } from "fluidstate-react";
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>
	);
};

In this example, the Counter component subscribes only to counterStore.count. If other properties were added to counterStore and changed, this component would not re-render unnecessarily.

withReactive HOC

The withReactive HOC provides an alternative way to make a component reactive. It wraps your component and automatically re-renders it when any reactive state accessed during its render cycle changes.

Here is the same counter example, but implemented with withReactive:

import { withReactive } from "fluidstate-react";
import { counterStore } from "./counter-store";

// Wrap the component with withReactive to make it reactive.
// Note: The component may receive reactive state via props or closure.
// For this example, we'll access the global `counterStore`.
const CounterComponent = withReactive(() => {
	return (
		<div>
			<h1>Counter: {counterStore.count}</h1>
			<button onClick={counterStore.increment}>Increment</button>
			<button onClick={counterStore.decrement}>Decrement</button>
		</div>
	);
});

withReactive is useful for wrapping components that might not use hooks, or for situations where you prefer the HOC pattern.

For larger applications, managing global state can become complex. createReactiveSetup helps by allowing you to create encapsulated state modules. It generates a set of tools — a Provider, a consumer hook, and an HOC — for a specific slice of state. This promotes better organization, testability, and reusability.

One of the features is the automatic side effects cleanup. Any reactions (such as data fetching or logging) returned from your state creation function in a reactions array will be automatically stopped when it unmounts, preventing resource leaks.

The Pattern

  • Define State: You define the shape of your state and a factory function to create it.
  • Create Setup: You call createReactiveSetup with your factory function.
  • Provide State: You use the generated ReactiveProvider to wrap a part of your component tree.
  • Consume State: Descendant components can access the state using the generated useReactiveState hook or withReactiveState HOC.

Example: User Profile Module

Let's build a module for managing user profile data.

1. Create the reactive setup

import {
	createReactive,
	Reaction,
	createReaction,
	cloneInert,
} from "fluidstate";
import { createReactiveSetup } from "fluidstate-react";

// This type is used to pass initial data to our state creator.
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 the provider, hook, and HOC and rename them to be more specific
export const {
	ReactiveProvider: UserProfileProvider,
	useReactiveState: useUserProfileState,
	withReactiveState: withUserProfileState,
	MockProvider: MockUserProfileProvider,
} = 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;
		},
	});

	// An example of a reaction that will be automatically cleaned up (stopped)
	// when the provider unmounts.
	const syncProfile = createReaction(() => {
		fetch(`api/syncProfile`, {
			method: "POST",
			body: JSON.stringify(cloneInert(data)),
		});
	});

	return {
		data,
		actions,
		reactions: [syncProfile],
	};
});

2. Provide the state

Wrap your application or a feature area with the generated UserProfileProvider.

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

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

3. Consume the state

Components can now consume the state using either the hook or the HOC.

Using the useReactiveState hook:

import { useUserProfileState } from "./user-profile-setup";
import type { ChangeEvent } from "react";

export const UserProfileEditor = () => {
	// Select the specific data and actions needed.
	// The component will only re-render if `state.data.name` or `state.data.email` changes.
	const { name, email, updateName, setEmail } = useUserProfileState(
		(state) => ({
			name: state.data.name,
			email: state.data.email,
			updateName: state.actions.updateName,
			setEmail: state.actions.setEmail,
		})
	);

	const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
		updateName(e.target.value);
	};

	const handleEmailChange = (e: ChangeEvent<HTMLInputElement>) => {
		setEmail(e.target.value);
	};

	return (
		<div>
			<h2>Edit Profile</h2>
			<div>
				<label>Name: </label>
				<input type="text" value={name} onChange={handleNameChange} />
			</div>
			<div>
				<label>Email: </label>
				<input type="email" value={email ?? ""} onChange={handleEmailChange} />
			</div>
		</div>
	);
};

Using the withReactiveState HOC:

import { withUserProfileState } from "./user-profile-setup";

export const UserProfileDisplay = withUserProfileState(({ state }) => {
	// The HOC will re-render this component whenever any property on `state` read here changes.
	return (
		<div>
			<h2>Current Profile</h2>
			<p>
				<strong>Name:</strong> {state.data.name}
			</p>
			<p>
				<strong>Email:</strong> {state.data.email ?? "Not set"}
			</p>
		</div>
	);
});

The createReactiveSetup pattern is ideal for building scalable applications by promoting clear separation of concerns between state logic and UI components. The generated MockProvider is also very useful for testing components in isolation.

API Reference

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

A React hook that subscribes a component to reactive state changes.

  • getState: () => T: A function that reads one or more properties from reactive state and returns a value. The component will re-render when any of the reactive dependencies accessed within this function change.
  • dependencyArray?: ReadonlyArray<unknown>: Optional. An array of dependencies, similar to useMemo or useEffect. If provided, the getState function will be called again when a value in this array changes.

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

A Higher-Order Component that makes a functional component reactive.

  • Component: The React functional component to wrap. The wrapped component will automatically re-render whenever any reactive state it accesses during render changes.

createReactiveSetup<SetupProps, State>(createState)

A factory function that creates a set of utilities for managing an encapsulated slice of state.

  • createState: (props: SetupProps) => State: A function that takes setupProps and returns the reactive state object. If the returned object contains a reactions property (an array of Reaction instances from fluidstate), they will be automatically stopped when the ReactiveProvider unmounts.

It returns a ReactiveSetup object with the following properties:

ReactiveProvider

A React Provider component. You must wrap the part of your application that needs access to this state within this provider. It accepts a setupProps prop, which is passed to your createState function to initialize the state.

useReactiveState

A React hook to consume the state within a descendant component of the ReactiveProvider. It takes a selector function (state: State) => T and returns the selected value. The component re-renders when the properties accessed inside the selector function change.

withReactiveState

A HOC that injects the entire state object as a state prop into the wrapped component. The component must be a descendant of the ReactiveProvider.

MockProvider

A React Provider component intended for testing or tools like Storybook. It allows you to provide a partial or complete mock state object directly via its value prop, bypassing the createState function.

createState

The original createState function you provided is returned for convenience, which can be useful for testing the state logic itself.

StateContext

The React Context object used by the Provider.

Utility Types

createReactiveSetup also enables several utility types for better type inference:

  • StateType<T>: Extracts the State type from a ReactiveProvider type.
  • SetupPropsType<T>: Extracts the SetupProps type from a ReactiveProvider type.
  • CreateStateType<T>: Extracts the type of the createState function from a ReactiveProvider type.

Keywords

state

FAQs

Package last updated on 19 Jun 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts