CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-zustand

A small, fast and scalable state management solution for React applications using simplified flux principles

Overview
Eval results
Files

react-integration.mddocs/

React Integration

React hooks and components for consuming Zustand stores with automatic re-rendering and selector support.

Capabilities

useStore Hook

Hook for consuming store state in React components with automatic re-rendering when selected state changes.

/**
 * Subscribe to entire store state
 * @param api - Store API to subscribe to
 * @returns Complete store state
 */
function useStore<S extends ReadonlyStoreApi<unknown>>(api: S): ExtractState<S>;

/**
 * Subscribe to selected portion of store state
 * @param api - Store API to subscribe to
 * @param selector - Function to select specific state slice
 * @returns Selected state slice
 */
function useStore<S extends ReadonlyStoreApi<unknown>, U>(
  api: S,
  selector: (state: ExtractState<S>) => U
): U;

Usage Examples:

import { create } from "zustand";

const useStore = create((set) => ({
  count: 0,
  name: "John",
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

// Subscribe to entire state
function FullStateComponent() {
  const state = useStore();
  return <div>Count: {state.count}, Name: {state.name}</div>;
}

// Subscribe to specific state slice
function CountComponent() {
  const count = useStore((state) => state.count);
  return <div>Count: {count}</div>;
}

// Complex selector
function DerivedStateComponent() {
  const isEven = useStore((state) => state.count % 2 === 0);
  return <div>Count is {isEven ? 'even' : 'odd'}</div>;
}

UseBoundStore Type

Combined hook and store API interface returned by the create function.

/**
 * Hook interface with store API methods
 * Can be called as a hook with optional selector
 */
type UseBoundStore<S extends ReadonlyStoreApi<unknown>> = {
  /** Subscribe to entire store state */
  (): ExtractState<S>;
  /** Subscribe to selected state slice */
  <U>(selector: (state: ExtractState<S>) => U): U;
} & S;

Usage Examples:

const useCounterStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

// Use as hook - entire state
function Component1() {
  const { count, increment } = useCounterStore();
  return <button onClick={increment}>Count: {count}</button>;
}

// Use as hook - with selector
function Component2() {
  const count = useCounterStore((state) => state.count);
  return <div>Count: {count}</div>;
}

// Access store API methods directly
function Component3() {
  const handleClick = () => {
    useCounterStore.getState().increment();
  };
  
  return <button onClick={handleClick}>Increment</button>;
}

// Subscribe imperatively
useEffect(() => {
  const unsubscribe = useCounterStore.subscribe((state, prevState) => {
    console.log('Count changed:', prevState.count, '->', state.count);
  });
  
  return unsubscribe;
}, []);

Traditional API with Equality Functions

Alternative API that provides custom equality function support for preventing unnecessary re-renders.

/**
 * Hook with custom equality function support
 * @param api - Store API to subscribe to
 * @returns Complete store state
 */
function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>>(
  api: S
): ExtractState<S>;

/**
 * Hook with selector and custom equality function
 * @param api - Store API to subscribe to  
 * @param selector - Function to select specific state slice
 * @param equalityFn - Custom equality function for comparing values
 * @returns Selected state slice
 */
function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>, U>(
  api: S,
  selector: (state: ExtractState<S>) => U,
  equalityFn?: (a: U, b: U) => boolean
): U;

/**
 * Create store with default equality function
 * @param initializer - Function that creates the initial state and actions
 * @param defaultEqualityFn - Default equality function for all selectors
 * @returns UseBoundStoreWithEqualityFn instance
 */
function createWithEqualityFn<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
  initializer: StateCreator<T, [], Mos>,
  defaultEqualityFn?: <U>(a: U, b: U) => boolean
): UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;

Usage Examples:

import { createWithEqualityFn, useStoreWithEqualityFn } from "zustand/traditional";

// Store with default equality function
const useStore = createWithEqualityFn(
  (set) => ({
    users: [],
    addUser: (user) => set((state) => ({ users: [...state.users, user] })),
  }),
  (a, b) => JSON.stringify(a) === JSON.stringify(b) // deep equality
);

// Use with custom equality function
function UserList() {
  const users = useStoreWithEqualityFn(
    useStore,
    (state) => state.users,
    (a, b) => a.length === b.length && a.every((user, i) => user.id === b[i].id)
  );
  
  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

ReadonlyStoreApi Type

Type for store APIs that only expose read operations, used for type safety in hooks.

/**
 * Read-only interface for store API
 * Excludes setState to prevent mutations from components
 */
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'getInitialState' | 'subscribe'>;

Performance Optimization Patterns

Best practices for optimizing React component re-renders with Zustand.

Selector Optimization:

// ❌ Bad - creates new object every render, causes unnecessary re-renders
const { user, posts } = useStore((state) => ({ 
  user: state.user, 
  posts: state.posts 
}));

// ✅ Good - select minimal state
const user = useStore((state) => state.user);
const posts = useStore((state) => state.posts);

// ✅ Good - use shallow comparison for objects
import { useShallow } from "zustand/react/shallow";
const { user, posts } = useStore(useShallow((state) => ({ 
  user: state.user, 
  posts: state.posts 
})));

Action Separation:

// ✅ Good - separate actions to prevent re-renders when actions change
const count = useStore((state) => state.count);
const increment = useStore((state) => state.increment);

// Or access actions directly from store
const handleIncrement = () => useStore.getState().increment();

Install with Tessl CLI

npx tessl i tessl/npm-zustand

docs

index.md

middleware.md

react-integration.md

store-creation.md

utilities.md

tile.json