Skip to content

React Integration

Create a hook for accessing store state:

import { createStore } from '@standard-store/store';
import { createStoreHook } from '@standard-store/react';
const store = createStore({ count: 0 });
const useStore = createStoreHook(store);
export default function Counter() {
const { count } = useStore();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => store.setState({ count: count + 1 })}>
Increment
</button>
</div>
);
}

Create separate hooks for different stores to isolate re-renders:

import { createStoreHook } from '@standard-store/react';
const userStore = createStore({ name: 'John' });
const settingsStore = createStore({ theme: 'light' });
const useUserStore = createStoreHook(userStore);
const useSettingsStore = createStoreHook(settingsStore);
function App() {
const user = useUserStore();
const settings = useSettingsStore();
return (
<div>
<h1>{user.name}</h1>
<p>Theme: {settings.theme}</p>
</div>
);
}

Select only the state you need to optimize performance:

const useCount = () => {
const { count } = useStore();
return count;
};
function Counter() {
const count = useCount();
return <div>{count}</div>; // Only re-renders when count changes
}

Combine store state with React hooks for advanced patterns:

import React, { useState, useEffect } from 'react';
const useCounterWithHistory = () => {
const store = useStore();
const [history, setHistory] = useState<number[]>([]);
// Subscribe to state changes and track history
useEffect(() => {
const unsubscribe = store.subscribe((state) => {
setHistory((h) => [...h, state.count]);
});
return unsubscribe;
}, []);
return { ...store, history };
};

Combine with React Context for provider pattern:

import React from 'react';
import { createStore } from '@standard-store/store';
import { createStoreHook } from '@standard-store/react';
const store = createStore({ count: 0 });
const StoreContext = React.createContext<typeof store | null>(null);
export function StoreProvider({ children }: { children: React.ReactNode }) {
return (
<StoreContext.Provider value={store}>
{children}
</StoreContext.Provider>
);
}
export function useStore() {
const context = React.useContext(StoreContext);
if (!context) {
throw new Error('useStore must be used within StoreProvider');
}
return context.getState();
}

Prevent unnecessary re-renders:

// Memoize the component
const Counter = React.memo(() => {
const { count } = useStore();
return <div>{count}</div>;
});
// Or memoize computed values
function Component() {
const { count, name } = useStore();
// Only recompute when dependencies change
const displayName = React.useMemo(() => `User ${name}`, [name]);
return <div>{displayName}</div>;
}

A complete todo list application:

interface Todo {
id: string;
text: string;
done: boolean;
}
const todoStore = createStore<{ todos: Todo[] }>({
todos: [],
});
const useTodos = createStoreHook(todoStore);
function TodoList() {
const { todos } = useTodos();
const addTodo = (text: string) => {
todoStore.setState({
todos: [
...todos,
{ id: Date.now().toString(), text, done: false },
],
});
};
const toggleTodo = (id: string) => {
todoStore.setState((state) => ({
todos: state.todos.map(t =>
t.id === id ? { ...t, done: !t.done } : t
),
}));
};
return (
<div>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.done}
onChange={() => toggleTodo(todo.id)}
/>
{todo.text}
</li>
))}
</ul>
<button onClick={() => addTodo('New todo')}>Add</button>
</div>
);
}