useDisposable
Manages synchronous disposable resources using the TC39 Explicit Resource Management proposal.
About
Bridges TC39 Explicit Resource Management (Symbol.dispose) with React lifecycles. It creates a disposable resource synchronously so the resource is available on the first render, and disposes it when the component unmounts or when the dependency array changes.
This hook requires Symbol.dispose 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 { useDisposable } from "rooks/experimental";
class ManagedWebSocket {
socket = new WebSocket("wss://example.com");
[Symbol.dispose]() {
this.socket.close();
}
}
function ChatRoom() {
const socket = useDisposable(() => new ManagedWebSocket(), []);
return <button onClick={() => socket.socket.send("hello")}>Send</button>;
}Recreate a disposable resource when dependencies change
import { useState } from "react";
import { useDisposable } from "rooks/experimental";
class UserScopedStore {
constructor(public userId: string) {}
[Symbol.dispose]() {
// clean up user-specific resources
}
}
export default function UserStorePanel() {
const [userId, setUserId] = useState("alice");
const store = useDisposable(() => new UserScopedStore(userId), [userId]);
return (
<div>
<button onClick={() => setUserId("bob")}>Switch user</button>
<p>Active store: {store.userId}</p>
</div>
);
}Parameters
| Argument | Type | Description | Default value |
|---|---|---|---|
factory | () => T | Function that creates the disposable resource | required |
deps | DependencyList | Dependency array controlling when the resource is replaced | [] |
Return value
| Return value | Type | Description |
|---|---|---|
resource | T | The disposable resource, available synchronously on every render |
Notes
- Import from
rooks/experimental, notrooks. rooksdoes not polyfillSymbol.disposefor you.- If the returned resource does not implement
[Symbol.dispose](), the hook throws a descriptive runtime error.
Behavior and lifecycle
The factory runs synchronously during render so the resource is immediately available. A dependency change disposes the old resource during effect cleanup, creates its replacement in the next effect, and forces a render; unmount invokes [Symbol.dispose]() once for the current resource. Development Strict Mode can create and dispose more than once, so the factory and disposer must tolerate replay.
Compatibility and accessibility
Because creation happens during render, the factory also runs during SSR and must not access browser globals unless guarded. Missing Symbol.dispose, a resource without the required method, a factory failure, or a disposal failure throws to the nearest error boundary. Load the polyfill before rendering in unsupported runtimes.