Guía de React

Aprende a crear sliders con @reelkit/react.

Táctil ante todo
Deslizamiento con inercia y ajuste
Teclado
Flechas + Escape
Rueda del ratón
Opcional, con debounce
Virtualizado
Más de 10.000 elementos, 3 en el DOM
Indicadores
Puntos que se desplazan al estilo de Instagram
API por código
next(), prev(), goTo() mediante ref
Modo bucle
Navegación circular infinita
Dirección
Vertical u horizontal
Sin re-renderizados
Actualizaciones de estado con señales

Componente Reel

El componente Reel es el contenedor principal: gestiona el estado del slider, los gestos táctiles, la navegación con teclado y las animaciones.

tsx
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>

Tamaño automático

La prop size es opcional. Sin ella, Reel mide su contenedor con ResizeObserver y se adapta al diseño que marque el CSS. El tamaño del contenedor lo tiene que dar su padre (por ejemplo, flex, grid o dimensiones explícitas en CSS).

tsx
// 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={...} />

Patrón itemBuilder

La prop itemBuilder es una función que recibe el índice y devuelve el contenido de cada slide. Este patrón hace posible la virtualización: solo se renderizan los elementos visibles.

tsx
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} />;
}}

Métodos de navegación incluidos:

  • Táctil / deslizar: arrastra para navegar con inercia y ajuste al slide
  • Teclado: teclas de flecha y Escape
  • Rueda del ratón: se activa con la prop enableWheel
  • Por código: usa apiRef para next(), prev(), goTo()
tsx
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>
    </>
  );
}

Estado en la URL

useOverlayUrlState crea un controlador de estado en la URL para un overlay y lo devuelve entero; después se lo pasas a un *UrlOverlay en su prop controller. La URL es dueña del estado abierto, así que un overlay vinculado se abre solo y lo habitual es abrirlo con un enlace. La primera escritura de un parámetro ausente añade una entrada al historial y las siguientes la sustituyen, así que pasar slides nunca entierra el botón de volver. Guarda el controlador para leer value/position y manejarlo por código: set(position) abre, set(null) cierra, y set es la misma escritura de bajo nivel que usa el overlay internamente al cambiar de slide.

tsx
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),
});

El objeto de opciones recibe param, codec y locator (los tres obligatorios), más un adapter opcional. param y adapter se leen en el primer renderizado y quedan fijos (vuelve a montar para cambiarlos), mientras que codec y locator se leen en cada uso, así que una búsqueda después de que la lista crezca o se reordene ve la lista actual. El codec y el locator son un par a juego que comparte el mismo Id, así que van juntos: para una galería simple con ?photo=3, usa ...urlIndexKey(() => images.length), que devuelve las dos mitades a la vez. urlIndexKey convierte el parámetro en el índice de un slide y lo limita con el recuento actual que devuelve el getter, así que un ?photo=99 desfasado o fuera de rango se rechaza y se limpia solo de la URL en lugar de abrir un slide que nunca se nombró. Pasa un getter y no un número para que el límite siga siendo correcto mientras crece un feed paginado. Envuelve createIndexLocator (la mitad del locator) y lo combina con indexCodec. Un feed paginado o una galería por identidad aporta su propio par de codec + locator. La tabla completa de opciones está en la referencia de la API de React.

ReelIndicator

Componente opcional que muestra indicadores de progreso al estilo de Instagram con la posición actual en el slider. Colocado dentro de un Reel, se conecta solo a los valores count y active del padre a través del contexto, sin conectar el estado a mano.

tsx
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} />

Demo en vivo: slider básico

Táctil / deslizar
Con inercia
Teclado
Flechas + Escape
Indicadores
Al estilo de Instagram
Navegación
Mediante apiRef
BasicSlider.tsx

Virtualized

Only 3 slides in DOM

Pruébalo: pulsa los botones para moverte entre los slides.

Puntos clave

  • Prop size

    Tupla opcional [width, height], u omítela para que el CSS marque el tamaño

  • itemBuilder

    Recibe el índice y devuelve el contenido del slide

  • apiRef

    Da acceso a los métodos del controlador para navegar

  • afterChange

    Sigue el índice actual para actualizar la interfaz

Demo en vivo: lista infinita

reelkit renderiza solo 3 slides en el DOM en todo momento (el actual, el anterior y el siguiente). Así el desplazamiento es fluido en listas de más de 10.000 elementos.

3 elementos en el DOM
Solo se renderizan los slides visibles
Más de 10.000 elementos
Sin tirones a ninguna escala
Memoria constante
Los mismos 3 nodos del DOM sea cual sea el recuento
goTo(n)
Salta a cualquier índice al instante
InfiniteList.tsx

10.000 elementos y solo 3 en el DOM. Usa los botones o escribe un número para saltar.

Demo en vivo: lista que crece

Simula un feed infinito en el que los elementos se cargan bajo demanda, como en TikTok o Instagram. Empieza con 20 elementos; desplázate cerca del final y verás llegar nuevos lotes automáticamente.

Recuento dinámico
Los elementos se cargan al desplazarte
Carga por lotes
20 elementos por lote
Virtualizado
Sigue habiendo solo 3 en el DOM
Indicador automático
Los puntos crecen con el contenido
GrowableList.tsx
1 / 20 (growing)

Desplázate hasta el final: los nuevos elementos se cargan solos. El contador y el indicador crecen a medida que llegan los lotes.

Consejos de rendimiento

  • Memoriza los arrays de datos

    Envuelve el array de elementos con useMemo. Una referencia nueva en cada renderizado provoca una actualización de count y un nuevo cálculo de los rangos visibles.

  • Mantén itemBuilder ligero

    Se ejecuta con cada cambio del rango visible (normalmente 3 slides). Evita dentro cálculos pesados o efectos secundarios.

  • Carga datos cerca del final

    Usa afterChange para detectar cuándo el usuario se acerca al final y pide el siguiente lote antes de que se quede sin slides (mira la demo de la lista que crece más arriba).

  • Desactiva la rueda en páginas con scroll

    Pon enableWheel={false} cuando el slider esté dentro de un diseño con scroll para no capturar el desplazamiento de la página.

Siguientes pasos