Skip to Content

useSingleton

Exports Size
loading...
Gzip Size
loading...
Brotli Size
Source Code
View on GitHub
Docs
Edit this page

The React documentation’s “Avoiding recreating the ref contents” pattern  as a hook.

Before:

function Video() { const playerRef = useRef(null); if (playerRef.current === null) { playerRef.current = new VideoPlayer(); } // ...

After:

function Video() { const playerRef = useSingleton(() => new VideoPlayer()); // ...

Usage

0

import { useCallback, useEffect } from 'react'; import { useSingleton } from 'foxact/use-singleton'; interface VideoProps { videoSrc: string; } function Video({ videoSrc }: VideoProps) { const playerRef = useSingleton(() => new VideoPlayer()); // callback ref to attach the player to the video element const videoElementCallbackRef = useCallback((el: HTMLVideoElement | null) => { if (el) { playerRef.current.attach(el); playerRef.current.load(videoSrc); } else { playerRef.current.destroy(); } }, [videoSrc]); return <video ref={videoElementCallbackRef} />; }

Delayed initialization

If you want to delay the initialization, you can return null or undefined in the initializer function and let useSingleton retry on the next render.

import { useState } from 'react'; import { useSingleton } from 'foxact/use-singleton'; function Component() { const [shouldInit, setShouldInit] = useState(false); const workerRef = useSingleton(() => { if (!shouldInit) { return null; } return HeavyInstance.create(); }); if (!shouldInit) { return ( <button onClick={() => setShouldInit(true)}> Initialize </button> ); return <div /> }

If you want to use useSingleton to conditionally create a singleton instance and don’t want to retry, you should return a non-nullish value:

const kNoInitialize = Symbol('no initialize'); function Component() { const playerRef = useSingleton<typeof kNoInitialize | VideoPlayer>(() => (Math.random() > 0.5 ? kNoInitialize : new VideoPlayer())); }