Unique Instances
By default, navigating to another page or hiding a component with If() destroys the component. Rendering it again creates a new instance.
Recreation resets internal state in interactive elements. For example, a playing video stops, a canvas drawing is lost, and form inputs reset.
Unique instances preserve a component while it moves within the application.
Creating Persistent Components
Wrapping a component function in createUnique() preserves its instance:
import { createUnique } from 'retend'; export const PersistentVideo = createUnique(() => { return ( <video src="https://example.com/video.mp4" controls autoplay> Your browser does not support the video tag. </video> ); });
If <PersistentVideo /> is rendered on the Home page and then on the About page, Retend moves the same component instance to the new location. The video retains its playback state.
Multiple Independent Instances
By default, uses of a unique component share one underlying instance. If <PersistentVideo /> is rendered in two places at the same time, the instance moves to the last rendered location.
Independent instances that can coexist are created with a unique id prop on each use:
// Two separate video players, each with their own state <PersistentVideo id="camera-1" /> <PersistentVideo id="camera-2" />
camera-1 and camera-2 are independent persistent instances.
Passing Props
Props for a unique component are provided to its function as one reactive Cell. The component can react when it moves to a location with different props.
import { createUnique, Cell } from 'retend'; const UniquePanel = createUnique((props) => { // 1. Create a derived Cell so the title automatically updates const title = Cell.derived(() => props.get().title); return ( <div class="panel"> <h2>{title}</h2> <p>This panel persists as it moves.</p> </div> ); }); // If rendered here... <UniquePanel id="panel-1" title="First Title" /> // And then later moved here... <UniquePanel id="panel-1" title="Updated Title" /> // The exact same component instance is used, but the <h2> text updates instantly!
Saving and Restoring Scroll Position
createUnique preserves the component instance, but some DOM state, such as scroll position, resets when the component moves between locations.
The onMove hook saves and restores that state:
import { createUnique, onMove, Cell } from 'retend'; const ScrollableArea = createUnique(() => { const ref = Cell.source<HTMLDivElement | null>(null); onMove(() => { const element = ref.get(); if (!element) return; const scrollPos = element.scrollTop; return () => { element.scrollTop = scrollPos; }; }); return ( <div ref={ref} style={{ height: '400px', overflow: 'auto' }}> <p>Lots of content here...</p> </div> ); });
The onMove hook runs before the unique component moves. A function returned from the hook runs after the move completes.
Unique instances suit components that retain internal state across navigation.