Store Hook
The store hook is what's returned from the create
function. It's the primary way to access and use your store's state.
Basic Usage
- TypeScript
- JavaScript
// Get a specific piece of state
const count = useCounterStore((state) => state.count);
// Get an action
const increment = useCounterStore((state) => state.increment);
// Get multiple values with useShallow to prevent unnecessary re-renders
import { useShallow } from '@mag1yar/zustand-context';
const { count, increment } = useCounterStore(
useShallow((state) => ({
count: state.count,
increment: state.increment,
})),
);
// Get a specific piece of state
const count = useCounterStore((state) => state.count);
// Get an action
const increment = useCounterStore((state) => state.increment);
// Get multiple values with useShallow to prevent unnecessary re-renders
import { useShallow } from '@mag1yar/zustand-context';
const { count, increment } = useCounterStore(
useShallow((state) => ({
count: state.count,
increment: state.increment,
})),
);
API Reference
Signature
- TypeScript
- JavaScript
function useStore<U>(selector?: (state: T) => U, options?: StoreOptions): U;
function useStore(
selector,
options
);
Parameters
selector (optional)
A function that extracts and returns values from the store's state. Accepts the full state and returns the derived value.
- TypeScript
- JavaScript
// Single value selector
useStore((state) => state.count);
// Multiple value selector with useShallow
useStore(
useShallow((state) => ({
count: state.count,
name: state.name,
})),
);
// Single value selector
useStore((state) => state.count);
// Multiple value selector with useShallow
useStore(
useShallow((state) => ({
count: state.count,
name: state.name,
})),
);
options (optional)
An options object for configuring hook behavior.
- TypeScript
- JavaScript
interface StoreOptions {
/** Access a specific store instance by ID */
from?: string;
}
{
// Access a specific store instance by ID
from: string;
}
The from
option specifies which store instance to access by its ID. It's used when you need to access a store instance other than the nearest one in the provider hierarchy.
Example Scenarios
Accessing the Nearest Provider
The default behavior is to access the nearest provider in the component tree:
- TypeScript
- JavaScript
function Counter() {
// Automatically connects to nearest Provider
const count = useCounterStore((state) => state.count);
const increment = useCounterStore((state) => state.increment);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
function Counter() {
// Automatically connects to nearest Provider
const count = useCounterStore((state) => state.count);
const increment = useCounterStore((state) => state.increment);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
Accessing a Specific Provider
You can access any provider in the hierarchy by its ID using the from
option:
- TypeScript
- JavaScript
function NestedComponent() {
// Access specifically named instances
const headerCount = useCounterStore((state) => state.count, { from: 'header' });
return (
<div>
<p>Header count: {headerCount}</p>
</div>
);
}
function NestedComponent() {
// Access specifically named instances
const headerCount = useCounterStore((state) => state.count, { from: 'header' });
return (
<div>
<p>Header count: {headerCount}</p>
</div>
);
}
Performance Optimization
Just like regular Zustand, the hook will only trigger re-renders when the selected state changes:
- TypeScript
- JavaScript
// This component only re-renders when count changes
function CountDisplay() {
const count = useCounterStore((state) => state.count);
return <div>{count}</div>;
}
// This component only re-renders when name changes
function NameDisplay() {
const name = useUserStore((state) => state.name);
return <div>{name}</div>;
}
// This component only re-renders when count changes
function CountDisplay() {
const count = useCounterStore((state) => state.count);
return <div>{count}</div>;
}
// This component only re-renders when name changes
function NameDisplay() {
const name = useUserStore((state) => state.name);
return <div>{name}</div>;
}
Using useShallow
For object selectors, you must use useShallow
to prevent unnecessary re-renders:
- TypeScript
- JavaScript
import { useShallow } from '@mag1yar/zustand-context';
function UserProfile() {
// Only re-renders when either firstName or lastName change
const { firstName, lastName } = useUserStore(
useShallow((state) => ({
firstName: state.firstName,
lastName: state.lastName,
})),
);
return (
<div>
{firstName} {lastName}
</div>
);
}
import { useShallow } from '@mag1yar/zustand-context';
function UserProfile() {
// Only re-renders when either firstName or lastName change
const { firstName, lastName } = useUserStore(
useShallow((state) => ({
firstName: state.firstName,
lastName: state.lastName,
})),
);
return (
<div>
{firstName} {lastName}
</div>
);
}
Handling Missing Providers
If a component tries to use a store without a Provider in strict mode, an error will be thrown:
- TypeScript
- JavaScript
// This will throw an error in strict mode if not inside a Provider
function Component() {
const count = useCounterStore((state) => state.count);
return <div>{count}</div>;
}
// This will throw an error in strict mode if not inside a Provider
function Component() {
const count = useCounterStore((state) => state.count);
return <div>{count}</div>;
}
You can handle this by:
- Making sure the component is used within a Provider
- Creating the store with
strict: false
to enable provider-optional mode - Adding custom error handling with the
onError
option