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

utilities.mddocs/

Utilities

Helper functions for shallow comparison, state optimization, and performance improvements in Zustand applications.

Capabilities

Shallow Comparison

Deep equality comparison function for optimizing React re-renders and state subscriptions.

/**
 * Performs shallow comparison between two values
 * Compares primitive values and top-level properties of objects/arrays
 * @param valueA - First value to compare
 * @param valueB - Second value to compare
 * @returns true if values are shallowly equal, false otherwise
 */
function shallow<T>(valueA: T, valueB: T): boolean;

Supported Data Types:

  • Primitives: strings, numbers, booleans, BigInt, symbols
  • Objects: plain objects (top-level properties only)
  • Arrays: element-by-element comparison
  • Maps: key-value pair comparison
  • Sets: element comparison (order independent)
  • Iterables: ordered element comparison
  • Functions: reference equality

Usage Examples:

import { shallow } from "zustand/shallow";

// Primitive comparisons
shallow(1, 1);                    // true
shallow("hello", "hello");        // true
shallow(true, false);             // false

// Object comparisons (shallow only)
shallow({ a: 1, b: 2 }, { a: 1, b: 2 });           // true
shallow({ a: 1, b: 2 }, { b: 2, a: 1 });           // true (order independent)
shallow({ a: { x: 1 } }, { a: { x: 1 } });         // false (nested objects)

// Array comparisons
shallow([1, 2, 3], [1, 2, 3]);                     // true
shallow([1, [2, 3]], [1, [2, 3]]);                 // false (nested arrays)

// Map comparisons
shallow(new Map([["a", 1]]), new Map([["a", 1]])); // true
shallow(new Map([["a", 1], ["b", 2]]), new Map([["b", 2], ["a", 1]])); // true

// Set comparisons
shallow(new Set([1, 2]), new Set([1, 2]));         // true
shallow(new Set([1, 2]), new Set([2, 1]));         // true (order independent)

// Mixed types
shallow(null, undefined);                           // false
shallow([], {});                                    // false

React Shallow Hook

React hook that provides memoized shallow comparison for optimizing selector functions.

/**
 * React hook for memoized shallow comparison of selector results
 * Prevents unnecessary re-renders when selector returns shallowly equal values
 * @param selector - Function that selects values from state
 * @returns Memoized selector function
 */
function useShallow<S, U>(selector: (state: S) => U): (state: S) => U;

Usage Examples:

import { create } from "zustand";
import { useShallow } from "zustand/react/shallow";

const useStore = create((set) => ({
  user: { name: "John", age: 30 },
  posts: [],
  preferences: { theme: "light", lang: "en" },
  updateUser: (updates) => set((state) => ({ 
    user: { ...state.user, ...updates } 
  })),
  addPost: (post) => set((state) => ({ 
    posts: [...state.posts, post] 
  })),
}));

// ❌ Bad - creates new object on every render, causes unnecessary re-renders
function UserProfile() {
  const { user, preferences } = useStore((state) => ({ 
    user: state.user, 
    preferences: state.preferences 
  }));
  
  return <div>{user.name} - {preferences.theme}</div>;
}

// ✅ Good - uses shallow comparison to prevent unnecessary re-renders
function UserProfileOptimized() {
  const { user, preferences } = useStore(
    useShallow((state) => ({ 
      user: state.user, 
      preferences: state.preferences 
    }))
  );
  
  return <div>{user.name} - {preferences.theme}</div>;
}

// ✅ Alternative - select individual properties
function UserProfileAlternative() {
  const user = useStore((state) => state.user);
  const preferences = useStore((state) => state.preferences);
  
  return <div>{user.name} - {preferences.theme}</div>;
}

// Complex selector with derived state
function PostSummary() {
  const summary = useStore(
    useShallow((state) => ({
      totalPosts: state.posts.length,
      userPosts: state.posts.filter(p => p.authorId === state.user.id),
      recentPosts: state.posts.slice(-5),
    }))
  );
  
  return (
    <div>
      <p>Total: {summary.totalPosts}</p>
      <p>Yours: {summary.userPosts.length}</p>
      <p>Recent: {summary.recentPosts.length}</p>
    </div>
  );
}

Traditional API with Custom Equality

Alternative store creation and hook APIs that support custom equality functions.

/**
 * Creates store with default equality function for all selectors
 * @param initializer - State creator function
 * @param defaultEqualityFn - Default equality function
 * @returns Store with equality function support
 */
function createWithEqualityFn<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
  initializer: StateCreator<T, [], Mos>,
  defaultEqualityFn?: <U>(a: U, b: U) => boolean
): UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;

/**
 * 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;

Usage Examples:

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

// Store with default shallow equality
const useStore = createWithEqualityFn(
  (set) => ({
    items: [],
    filters: { category: "all", active: true },
    addItem: (item) => set((state) => ({ 
      items: [...state.items, item] 
    })),
    updateFilters: (newFilters) => set((state) => ({ 
      filters: { ...state.filters, ...newFilters } 
    })),
  }),
  shallow // Default equality function for all selectors
);

// Component using default equality
function ItemList() {
  const { items, filters } = useStore(); // Uses shallow comparison
  
  return (
    <div>
      {items
        .filter(item => filters.category === "all" || item.category === filters.category)
        .map(item => <div key={item.id}>{item.name}</div>)}
    </div>
  );
}

// Component with custom equality function
function FilteredItems() {
  const filteredItems = useStoreWithEqualityFn(
    useStore,
    (state) => state.items.filter(item => 
      state.filters.category === "all" || item.category === state.filters.category
    ),
    (prevItems, currItems) => 
      prevItems.length === currItems.length && 
      prevItems.every((item, i) => item.id === currItems[i].id)
  );
  
  return (
    <div>
      {filteredItems.map(item => <div key={item.id}>{item.name}</div>)}
    </div>
  );
}

// Deep equality for complex objects
function UserSettings() {
  const settings = useStoreWithEqualityFn(
    useStore,
    (state) => state.user.settings,
    (prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)
  );
  
  return (
    <div>
      <p>Theme: {settings.theme}</p>
      <p>Language: {settings.language}</p>
    </div>
  );
}

Performance Optimization Patterns

Best practices for using utilities to optimize application performance.

Selector Optimization

import { create } from "zustand";
import { useShallow } from "zustand/react/shallow";

const useStore = create((set) => ({
  user: { id: 1, name: "John", email: "john@example.com" },
  posts: [],
  comments: [],
  ui: { loading: false, theme: "light" },
  // ... actions
}));

// ❌ Avoid - selecting entire state causes re-renders on any change
function BadComponent() {
  const state = useStore();
  return <div>{state.user.name}</div>;
}

// ❌ Avoid - new object on every render
function BadSelectorComponent() {
  const data = useStore((state) => ({ 
    user: state.user, 
    postCount: state.posts.length 
  }));
  return <div>{data.user.name} has {data.postCount} posts</div>;
}

// ✅ Good - specific property selection
function GoodComponent() {
  const userName = useStore((state) => state.user.name);
  return <div>{userName}</div>;
}

// ✅ Good - shallow comparison for multiple properties
function GoodMultiSelectComponent() {
  const { user, postCount } = useStore(
    useShallow((state) => ({ 
      user: state.user, 
      postCount: state.posts.length 
    }))
  );
  return <div>{user.name} has {postCount} posts</div>;
}

Action Optimization

// ✅ Good - separate action selectors to prevent re-renders
function OptimizedComponent() {
  const userName = useStore((state) => state.user.name);
  const updateUser = useStore((state) => state.updateUser);
  
  // Actions don't change, so no re-renders from action updates
  return (
    <div>
      <p>{userName}</p>
      <button onClick={() => updateUser({ name: "Jane" })}>
        Update Name
      </button>
    </div>
  );
}

// ✅ Alternative - access actions imperatively
function ImperativeActionsComponent() {
  const userName = useStore((state) => state.user.name);
  
  const handleUpdate = () => {
    useStore.getState().updateUser({ name: "Jane" });
  };
  
  return (
    <div>
      <p>{userName}</p>
      <button onClick={handleUpdate}>Update Name</button>
    </div>
  );
}

Custom Equality Functions

// Optimized equality functions for different use cases

// Array comparison by length and key properties
const arrayByIds = (prev, curr) => 
  prev.length === curr.length && 
  prev.every((item, i) => item.id === curr[i].id);

// Object comparison by specific properties
const userByBasicInfo = (prev, curr) =>
  prev.id === curr.id && 
  prev.name === curr.name && 
  prev.email === curr.email;

// Date comparison
const dateEquality = (prev, curr) => 
  prev.getTime() === curr.getTime();

// Usage in components
function OptimizedUserList() {
  const users = useStoreWithEqualityFn(
    useStore,
    (state) => state.users,
    arrayByIds
  );
  
  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

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