React-Leitfaden
So baust du Slider mit @reelkit/react.
Reel-Komponente
Die Komponente Reel ist der Hauptcontainer, der den Zustand des Sliders verwaltet und sich um Touch-Gesten, Tastaturnavigation und Animationen kümmert.
Im DOM liegen immer nur drei Slides, der aktuelle und seine Nachbarn, daher kostet eine Liste mit zehntausend Einträgen so viel wie eine mit zehn. Wie das in einem ganzen Feature aussieht, etwa in einem endlosen Feed oder einem Raster, das einen Player öffnet, zeigen die Rezepte.
import { Reel, ReelIndicator } from '@reelkit/react';
<Reel
count={items.length}
size={[width, height]}
direction="vertical"
enableWheel
afterChange={(index) => console.log('Current:', index)}
itemBuilder={(index, indexInRange, size) => (
<div style={{ width: size[0], height: size[1] }}>
Slide {index}
</div>
)}
>
{/* Optional children like ReelIndicator */}
</Reel>Automatische Größe
Das Prop size ist optional. Lässt du es weg, misst Reel seinen Container per ResizeObserver selbst aus und passt sich dem Layout aus dem CSS an. Die Größe des Containers muss dabei vom Elternelement kommen (zum Beispiel Flex, Grid oder feste Maße im CSS).
// Explicit size (fixed)
<Reel count={items.length} size={[400, 600]} itemBuilder={...} />
// Auto-size (responsive — sized by CSS)
<Reel count={items.length} style={{ width: '100%', height: '100dvh' }} itemBuilder={...} />Das itemBuilder-Muster
Das Prop itemBuilder ist eine Funktion, die den Index bekommt und den Inhalt des jeweiligen Slides zurückgibt. Dieses Muster macht die Virtualisierung möglich: Gerendert werden nur die sichtbaren Einträge.
itemBuilder={(index, indexInRange, size) => {
// index: actual item index (0 to count-1)
// indexInRange: position in visible window (0, 1, or 2)
// size: [width, height] of the container
return <Slide index={index} />;
}}Navigation
Eingebaute Wege der Navigation:
- Touch/Wischen: Ziehen mit Schwung und Einrasten
- Tastatur: Pfeiltasten und Escape
- Mausrad: Aktivierst du mit dem Prop
enableWheel - Im Code: Über
apiRefmitnext(),prev(),goTo()
import { useRef } from 'react';
import { Reel, type ReelApi } from '@reelkit/react';
function App() {
const apiRef = useRef<ReelApi>(null);
return (
<>
<Reel
count={10}
size={[400, 600]}
apiRef={apiRef}
itemBuilder={(index) => <Slide index={index} />}
/>
<button onClick={() => apiRef.current?.prev()}>Prev</button>
<button onClick={() => apiRef.current?.next()}>Next</button>
<button onClick={() => apiRef.current?.goTo(5)}>Go to 5</button>
</>
);
}URL-State
useOverlayUrlState baut einen URL-State-Controller für ein Overlay und gibt ihn vollständig zurück. Den übergibst du dann einem *UrlOverlay als Prop controller. Die URL bestimmt, ob es offen ist, ein gebundenes Overlay öffnet sich also selbst, und ein Link ist der übliche Weg, es zu öffnen. Das erste Schreiben eines noch fehlenden Parameters legt einen Eintrag im Verlauf an, jedes weitere ersetzt ihn, so begräbt das Blättern nie den Zurück-Button. Behalte den Controller, um value/position zu lesen und ihn im Code zu steuern: set(position) öffnet, set(null) schließt, und set ist derselbe einfache Schreibzugriff, den das Overlay intern beim Slide-Wechsel nutzt.
import { useOverlayUrlState, urlIndexKey } from '@reelkit/react';
import { useReactRouterUrlAdapter } from '@reelkit/react/react-router-url-adapter';
import { LightboxUrlOverlay } from '@reelkit/react-lightbox';
import { Link } from 'react-router-dom';
const photo = useOverlayUrlState({
param: 'photo',
...urlIndexKey(() => images.length),
});
// Opening is a link — the overlay reads the URL and opens itself.
<Link to="?photo=3"><img src={images[3].src} /></Link>
<LightboxUrlOverlay controller={photo} images={images} />
// Read the url-derived state, or close programmatically (a low-level write).
photo.position.value; // 3 for ?photo=3, null when nothing is open
photo.set(null); // close
// Routed app: pass a router-backed adapter, otherwise the router's
// own location goes stale and its next navigation drops the param.
const adapter = useReactRouterUrlAdapter();
const routed = useOverlayUrlState({
param: 'photo',
adapter,
...urlIndexKey(() => images.length),
});Das Optionsobjekt nimmt param, codec und locator (alle drei Pflicht) sowie einen optionalen adapter. param und adapter werden beim ersten Render gelesen und bleiben danach fest – zum Ändern musst du neu mounten –, während codec und locator live gelesen werden, sodass eine Suche nach dem Wachsen oder Umsortieren der Liste die aktuelle Liste sieht. codec und locator sind ein zusammengehöriges Paar mit demselben Id und reisen deshalb gemeinsam – für eine einfache Galerie mit ?photo=3 spreizt du ...urlIndexKey(() => images.length), das beide Hälften auf einmal zurückgibt. urlIndexKey bildet den Parameter auf einen Slide-Index ab und begrenzt ihn mit der aktuellen Anzahl, die der Getter liefert. Ein veraltetes oder zu großes ?photo=99 wird so abgelehnt und verschwindet von selbst aus der URL, statt einen Slide zu öffnen, den nie jemand gemeint hat. Übergib einen Getter, keine Zahl, damit die Grenze stimmt, während ein Feed mit Paginierung wächst. Es kapselt createIndexLocator (die Locator-Hälfte) und kombiniert es mit indexCodec. Ein Feed mit Paginierung oder eine Galerie mit Schlüsseln nach Identität bringt stattdessen ein eigenes passendes Paar aus codec + locator mit. Die vollständige Tabelle der Optionen steht in der React-API-Referenz.
ReelIndicator
Optionale Komponente, die Fortschrittsindikatoren wie bei Instagram zeigt und damit die aktuelle Position im Slider. Liegt sie in einem Reel, verbindet sie sich über den Context selbst mit den Werten count und active des Elternelements – ganz ohne manuelles Verdrahten von Zustand.
import { Reel, ReelIndicator } from '@reelkit/react';
{/* Auto-connect: count and active are inherited from parent Reel */}
<Reel count={10} size={[400, 600]} itemBuilder={...}>
<ReelIndicator />
</Reel>
{/* Manual usage: pass count and active explicitly (e.g. outside a Reel) */}
<ReelIndicator count={10} active={currentIndex} />Das Wichtigste
- Prop size
Optionales Tupel [width, height]; lass es weg, wenn die Größe aus dem CSS kommen soll
- itemBuilder
Bekommt den Index und gibt den Inhalt des Slides zurück
- apiRef
Zugriff auf die Methoden des Controllers für die Navigation
- afterChange
Verfolgt den aktuellen Index für Updates der UI
Tipps für die Performance
- Datenarrays memoisieren
Umschließe dein Array mit Einträgen mit
useMemo. Eine neue Array-Referenz bei jedem Render löst ein Update voncountaus und berechnet die sichtbaren Bereiche neu. - itemBuilder schlank halten
Er läuft bei jeder Änderung des sichtbaren Bereichs (meist 3 Slides). Vermeide darin aufwendige Berechnungen oder Seiteneffekte.
- Daten kurz vor dem Ende laden
Erkenne mit
afterChange, wann sich der Nutzer dem Ende nähert, und lade den nächsten Schwung, bevor ihm die Slides ausgehen (siehe das Rezept „Endloser Feed“). - Mausrad auf scrollbaren Seiten abschalten
Setze
enableWheel={false}, wenn der Slider in einem scrollbaren Layout steckt, damit er das Scrollen der Seite nicht abfängt.
Nächste Schritte
- API-Referenz - alle verfügbaren Props
- Reel Player - Videoplayer im Stil von TikTok/Reels
- Lightbox - Galerie für Bilder und Videos
- Stories Player - Stories-Ansicht im Stil von Instagram