
Security News
Open Source Maintainers Feeling the Weight of the EU’s Cyber Resilience Act
The EU Cyber Resilience Act is prompting compliance requests that open source maintainers may not be obligated or equipped to handle.
fluidstate-react
Advanced tools
Library for using fine-grained reactivity state management library fluidstate in 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.
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.fluidstate
ecosystem.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
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.
The two primary ways to make your components reactive are the useReactive
hook and the withReactive
HOC.
useReactive
HookThe 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
HOCThe 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.
createReactiveSetup
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.
createReactiveSetup
with your factory function.ReactiveProvider
to wrap a part of your component tree.useReactiveState
hook or withReactiveState
HOC.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.
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.
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.FAQs
Library for using fine-grained reactivity state management library fluidstate in React
The npm package fluidstate-react receives a total of 15 weekly downloads. As such, fluidstate-react popularity was classified as not popular.
We found that fluidstate-react demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
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.
Security News
The EU Cyber Resilience Act is prompting compliance requests that open source maintainers may not be obligated or equipped to handle.
Security News
Crates.io adds Trusted Publishing support, enabling secure GitHub Actions-based crate releases without long-lived API tokens.
Research
/Security News
Undocumented protestware found in 28 npm packages disrupts UI for Russian-language users visiting Russian and Belarusian domains.