Rooks
HooksExperimental Hooks

useAsyncDisposable

Manages async disposable resources using the TC39 Explicit Resource Management proposal.

About

Bridges TC39 Explicit Resource Management (Symbol.asyncDispose) with React lifecycles. It asynchronously creates a disposable resource and disposes it when the component unmounts or when the dependency array changes.

This hook requires Symbol.asyncDispose support at runtime. Browsers such as Safari currently need a polyfill. Load one like core-js/proposals/explicit-resource-management before using this hook.

Examples

Basic usage

import { useAsyncDisposable } from "rooks/experimental";

class ManagedConnection {
  async [Symbol.asyncDispose]() {
    // close the resource
  }
}

async function openConnection() {
  return new ManagedConnection();
}

function Screen() {
  const connection = useAsyncDisposable(() => openConnection(), []);

  if (connection === null) {
    return <div>Loading...</div>;
  }

  return <div>Ready</div>;
}

Recreate the resource when dependencies change

import { useState } from "react";
import { useAsyncDisposable } from "rooks/experimental";

class UserScopedConnection {
  constructor(public userId: string) {}

  async [Symbol.asyncDispose]() {
    // close the user-specific resource
  }
}

async function openUserConnection(userId: string) {
  return new UserScopedConnection(userId);
}

function UserConnectionPanel() {
  const [userId, setUserId] = useState("alice");
  const resource = useAsyncDisposable(
    () => openUserConnection(userId),
    [userId]
  );

  return (
    <div>
      <button onClick={() => setUserId("bob")}>Switch user</button>
      <div>{resource ? `Connected as ${resource.userId}` : "Loading..."}</div>
    </div>
  );
}

Parameters

ArgumentTypeDescriptionDefault value
factory() => Promise<T>Async function that creates the resourcerequired
depsDependencyListDependency array controlling when the resource is replaced[]

Return value

Return valueTypeDescription
resourceT | nullThe resource, or null while the factory is still resolving

Notes

  • Import from rooks/experimental, not rooks.
  • rooks does not polyfill Symbol.asyncDispose for you.
  • If deps change before the factory resolves, the stale resource is disposed immediately when it arrives.

Behavior and lifecycle

The factory starts from an effect and the hook returns null until it resolves. A dependency change or unmount clears the published resource and invokes [Symbol.asyncDispose]() without blocking React cleanup. If an obsolete factory resolves later, its resource is disposed immediately instead of being published. Development Strict Mode can create and dispose more than once, so both operations must be safe to repeat.

Compatibility and accessibility

SSR returns null because the factory runs only on the client. Missing Symbol.asyncDispose support throws from the effect. Factory rejections are not converted into hook state, and asynchronous disposal failures are intentionally ignored; handle or report failures inside those functions. Load the polyfill before React mounts when the runtime lacks the symbol.

On this page