CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-cache

A basic cache for React applications designed for experimental features with suspense-based data fetching

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

React Cache

React Cache is a basic cache for React applications that provides suspense-based data fetching capabilities. It serves as a reference implementation for more advanced caching solutions and is designed to work alongside experimental React features.

⚠️ Experimental Package: This package is explicitly unstable and not recommended for production use. The API will change between versions.

Package Information

  • Package Name: react-cache
  • Package Type: npm
  • Language: JavaScript (with Flow types)
  • Installation: This is a private package within the React monorepo and not directly installable
  • React Version: Requires React ^17.0.0 (peer dependency)

Core Imports

import { unstable_createResource, unstable_setGlobalCacheLimit } from "react-cache";

CommonJS:

const { unstable_createResource, unstable_setGlobalCacheLimit } = require("react-cache");

Basic Usage

import React, { Suspense } from "react";
import { unstable_createResource } from "react-cache";

// Create a resource for fetching user data
const UserResource = unstable_createResource(
  async (userId) => {
    const response = await fetch(`/api/users/${userId}`);
    return response.json();
  },
  (userId) => `user-${userId}` // Optional hash function for cache keys
);

function UserProfile({ userId }) {
  // This will suspend if data is not cached, or return cached data
  const user = UserResource.read(userId);
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <UserProfile userId={123} />
    </Suspense>
  );
}

Architecture

React Cache is built around several key components:

  • Resource Pattern: Resources encapsulate async data fetching with built-in caching
  • Suspense Integration: Uses React's suspense mechanism by throwing promises during pending states
  • LRU Cache: Internal Least Recently Used cache with configurable limits and automatic cleanup
  • Status Tracking: Three-state system (Pending/Resolved/Rejected) for cache entries
  • Hash Functions: Customizable key generation for cache storage

Capabilities

Resource Creation

Creates a cached resource that integrates with React Suspense for data fetching.

/**
 * Creates a resource that can cache async data fetching results
 * @param fetch - Function that returns a thenable (promise-like) for data fetching
 * @param maybeHashInput - Optional hash function for generating cache keys (defaults to identity function)
 * @returns Resource object with read and preload methods
 */
function unstable_createResource<I, K, V>(
  fetch: (input: I) => Thenable<V>,
  maybeHashInput?: (input: I) => K
): Resource<I, V>;

interface Resource<I, V> {
  /** 
   * Reads cached data or suspends if data is not available
   * Throws the promise if pending, throws error if rejected, returns value if resolved
   */
  read(input: I): V;
  
  /** 
   * Preloads data into cache without returning the value
   * Useful for prefetching data before it's needed
   */
  preload(input: I): void;
}

Usage Example:

// Simple resource with identity hash function
const SimpleResource = unstable_createResource(async (id) => {
  return fetch(`/api/data/${id}`).then(r => r.json());
});

// Resource with custom hash function for complex inputs
const ComplexResource = unstable_createResource(
  async ({ userId, type, filters }) => {
    const params = new URLSearchParams({ userId, type, ...filters });
    return fetch(`/api/complex?${params}`).then(r => r.json());
  },
  ({ userId, type, filters }) => `${userId}-${type}-${JSON.stringify(filters)}`
);

// Preload data before component renders
ComplexResource.preload({ userId: 123, type: 'profile', filters: { active: true } });

Global Cache Configuration

Sets the global cache limit for all resources.

/**
 * Sets the global cache limit for all resources
 * @param limit - Maximum number of cached entries across all resources
 */
function unstable_setGlobalCacheLimit(limit: number): void;

Usage Example:

import { unstable_setGlobalCacheLimit } from "react-cache";

// Set global cache to hold maximum 1000 entries
unstable_setGlobalCacheLimit(1000);

// Default limit is 500 entries

Types

Resource Interface

/**
 * Resource interface for cached data fetching
 */
interface Resource<I, V> {
  read(input: I): V;
  preload(input: I): void;
}

Core Types

/**
 * Promise-like interface used by React Cache
 */
interface Thenable<T> {
  then<U>(
    onFulfill?: (value: T) => U | Thenable<U>,
    onReject?: (error: any) => U | Thenable<U>
  ): Thenable<U>;
}

Cache Entry States

/**
 * Internal cache entry result types (for reference)
 */
type PendingResult = {
  status: 0;
  value: Thenable<any>; // The suspender thenable
};

type ResolvedResult<V> = {
  status: 1;
  value: V;
};

type RejectedResult = {
  status: 2;
  value: any; // The error
};

type Result<V> = PendingResult | ResolvedResult<V> | RejectedResult;

Error Handling

React Cache integrates with React's error boundaries for error handling:

// Errors thrown by fetch functions will be re-thrown when read() is called
const ErrorProneResource = unstable_createResource(async (id) => {
  const response = await fetch(`/api/data/${id}`);
  if (!response.ok) {
    throw new Error(`Failed to fetch: ${response.status}`);
  }
  return response.json();
});

function ErrorBoundary({ children }) {
  return (
    <React.ErrorBoundary
      fallback={<div>Something went wrong!</div>}
      onError={(error) => console.error('Cache error:', error)}
    >
      {children}
    </React.ErrorBoundary>
  );
}

Important Constraints

  • Render Phase Only: read() and preload() methods can only be called during React component render phase
  • Suspense Required: Components using resource.read() must be wrapped in a <Suspense> boundary
  • Key Limitations: Default hash function only supports primitive types (string, number, symbol, boolean, null, undefined)
  • React Version: Requires React 17.0.0 or higher
  • Experimental Status: API is subject to breaking changes without notice

docs

index.md

tile.json