Esta página se tradujo automáticamente y puede contener errores. Leer el original en inglés

API

List

nsh exporta List: una lista virtualizada sobre una scroll view nativa. Solo existen las filas cercanas al viewport, y sus celdas se reutilizan a medida que se desplaza. Qué filas existen, dónde están, las columnas, los encabezados fijos y la visibilidad se calculan de forma nativa, así que desplazar una lista de diez mil elementos no ejecuta nada de JS, salvo los bindings de fila que cambian cuando se reutiliza una celda.

import { List, type ListProps, type ViewToken, type ViewabilityConfig } from "nsh";

Consulta Lists para la guía y <List> para las props del elemento.

#List

function List<T>(props: ListProps<T>): JSX.Element;
import { List, mount, Text, View } from "nsh";

const contacts = Array.from({ length: 1000 }, (_, i) => ({ id: String(i), name: `Contact ${i}` }));

function App() {
  return (
    <List each={contacts} estimatedItemSize={48} style={{ flex: 1 }}>
      {(item, index) => (
        <View style={{ height: 48, paddingHorizontal: 16, justifyContent: "center", backgroundColor: index() % 2 ? "#f8fafc" : "#fff" }}>
          <Text>{item().name}</Text>
        </View>
      )}
    </List>
  );
}

mount(App);

#Las filas se reciclan

children es una función que renderiza una celda. Se ejecuta una vez por celda, no una vez por elemento: cuando una celda sale de la vista se reutiliza para otro elemento, y item() y index() (ambos accessors) cambian. Léelos dentro de expresiones JSX ({item().name}) para que la celda se actualice cuando se reutilice.

#Props

ListProps<T> combina las props propias de la lista con las props de desplazamiento que comparte con <Scroll> y las props que acepta todo elemento, que van a la scroll view de la lista.

#Datos y renderizado

Prop Tipo Valor por defecto Descripción
each readonly T[] (obligatorio) Los elementos. Pasa el valor de una signal (each={items()}) para seguir los cambios; insertar elementos por encima de las filas visibles mantiene esas filas en su sitio.
children (item: () => T, index: () => number) => JSX.Element (obligatorio) Renderiza una fila (véase arriba).
estimatedItemSize number 50 El tamaño de las filas aún no medidas, en puntos, a lo largo del eje de la lista. Unas estimaciones cercanas hacen más precisos el indicador de desplazamiento y scrollToIndex.
numColumns number 1 Elementos por fila (listas verticales): una cuadrícula.
horizontal boolean false Se desplaza horizontalmente.
inverted boolean false Se dispone desde el final, con el elemento 0 en último lugar (estilo chat); empieza desplazada al final y mantiene su distancia al final cuando cambia el contenido.
stickyHeaderIndices number[] Elementos que se quedan fijos al inicio mientras se desplaza más allá (una columna, sin invertir).
header ListSlot Se renderiza antes de los elementos.
footer ListSlot Se renderiza después de los elementos.
empty ListSlot Se muestra en lugar de los elementos mientras each está vacío.
separator ListSlot Se renderiza entre elementos (una columna).
keyExtractor (item: T, index: number) => string item.key, item.id o el índice La clave de un elemento en los tokens de visibilidad.
initialScrollIndex number Se desplaza a este elemento antes del primer frame.
contentStyle ListContentStyle Padding y espacios del contenido: padding, paddingHorizontal, paddingVertical, paddingTop, paddingRight, paddingBottom, paddingLeft, gap, rowGap, columnGap (números).
contentClass string Padding y espacios del contenido como clases (p-*, gap-*); contentStyle tiene prioridad sobre ellas.
style StyleProp<ViewStyle> El estilo propio de la lista (dale un tamaño: flex: 1 o una altura).
testID string El id con el que las pruebas de UI encuentran la scroll view de la lista (el id: de nsh test, XCUITest, UI Automator).
ref ListRef | ((node: ListRef) => void) Consulta los métodos de ref.

ListSlot es un componente (Header) o un elemento (<Header />).

#Carga, actualización y visibilidad

Prop Tipo Valor por defecto Descripción
onLoadMore () => void Se llama cuando el final queda a menos de loadMoreThreshold viewports: cargar más.
loadMoreThreshold number 1 Qué tan cerca del final (en longitudes de viewport) se dispara onLoadMore.
onLoadMoreAtStart () => void Se llama cuando el inicio queda a menos de loadMoreAtStartThreshold viewports después de que el usuario o un comando de desplazamiento moviera la lista: carga lo que viene antes del primer elemento.
loadMoreAtStartThreshold number 1 Qué tan cerca del inicio (en longitudes de viewport) se dispara onLoadMoreAtStart.
refreshing boolean Se muestra el spinner de pull-to-refresh.
onRefresh () => void Activa pull to refresh; establece refreshing mientras cargas.
refreshIndicator { height: number } La app dibuja su propio indicador de pull-to-refresh, de height de alto, en lugar del spinner.
pullValue AnimatedValue Recibe cuánto se ha tirado de la lista más allá de su parte superior, para ese indicador.
onViewableItemsChange (info: { viewableItems: ViewToken<T>[]; changed: ViewToken<T>[] }) => void Elementos que pasaron a ser visibles o dejaron de serlo.
viewabilityConfig ViewabilityConfig Cuándo se considera visible un elemento.
interface ViewToken<T> {
  item: T;
  key: string;
  index: number;
  isViewable: boolean;
}

interface ViewabilityConfig {
  /** How much of the viewport an item must cover to count as viewable, from 0 to 1. */
  viewAreaCoverageThreshold?: number;
  /** How much of an item must be visible, from 0 to 1. Without either threshold, any visible pixel counts. */
  itemVisibleThreshold?: number;
  /** Milliseconds items must stay viewable before they are reported. */
  minimumViewTime?: number;
}

#Desplazamiento

Prop Tipo Valor por defecto Descripción
scrollbar boolean | ScrollbarTheme true Se muestra el indicador de desplazamiento: el de la plataforma o la barra integrada de la app; un objeto es un tema de la propia vista.
scrollable boolean true El usuario puede desplazarla.
bounces boolean true Overscroll más allá de los bordes.
pagingEnabled boolean false Se detiene en múltiplos del viewport.
snapToInterval number 0 Se detiene en múltiplos de esta longitud (0: desactivado).
snapToOffsets number[] Se detiene en estos offsets.
snapToAlignment "start" | "center" | "end" "start" Qué punto de un elemento se alinea con el viewport con snapToInterval.
disableIntervalMomentum boolean false Un fling avanza como máximo un punto de anclaje.
decelerationRate "normal" | "fast" | number plataforma Qué tan rápido se frena un fling (0.998 / 0.99, o la velocidad que se conserva por milisegundo).
contentInset Partial<Edges> Espacio alrededor del contenido.
contentOffset { x?, y? } Dónde empieza.
keyboardShouldPersistTaps "never" | "always" | "handled" | boolean "never" Si un toque cierra el teclado ("never": el toque solo lo cierra).
keyboardDismissMode "none" | "on-drag" | "interactive" "none" Si arrastrar cierra el teclado.
scrollEventThrottle number Milisegundos mínimos entre eventos onScroll (como máximo uno por frame de todos modos).
scrollValue AnimatedValue Un valor animado que recibe el offset de desplazamiento (eje principal) en el hilo de UI, para efectos vinculados al desplazamiento.

#Eventos de desplazamiento

Evento Payload Cuándo
onScroll ScrollEvent: { offset, contentSize, size, zoomScale } Mientras se desplaza.
onScrollDragStart { offset } Empieza un arrastre.
onScrollDragEnd { offset } El dedo se levanta.
onMomentumStart { offset } Empieza un deslizamiento tras el arrastre.
onMomentumEnd { offset } El deslizamiento termina (también cuando un nuevo arrastre lo detiene).
onScrollEnd { offset } El desplazamiento se detuvo.

Las listas también aceptan las props que acepta todo elemento (props comunes).

#Métodos de ref

El ref de una lista recibe un ListRef, con estos métodos además de los de ViewRef:

Método Descripción
scrollToIndex({ index, animated?, viewPosition?, viewOffset? }) Desplaza el elemento index hasta que quede a la vista. viewPosition lo coloca: 0 al inicio del viewport (por defecto), 0.5 en el centro, 1 al final; viewOffset lo desplaza aún más. Se resuelve de forma nativa con los tamaños de fila medidos (o estimados).
scrollToOffset({ offset, animated? }) Se desplaza a un offset del contenido a lo largo del eje de la lista.
scrollToEnd({ animated? }) Se desplaza al final del contenido (el inicio de una lista invertida).
scrollTo({ x?, y?, animated? }) Se desplaza a un offset.
import { List, type ListRef, Text, View } from "nsh";

let list!: ListRef;

<View style={{ flex: 1 }}>
  <Text onPress={() => list.scrollToIndex({ index: 60, viewPosition: 0.5 })}>Jump to 60</Text>
  <List ref={list} each={items} numColumns={3} estimatedItemSize={90} style={{ flex: 1 }}
        contentStyle={{ padding: 12, gap: 8 }}>
    {(item) => <View style={{ height: 90, backgroundColor: "#e0e7ff" }}><Text>{item().title}</Text></View>}
  </List>
</View>

#Ejemplos

Un chat: el mensaje más reciente abajo, los mensajes más antiguos se cargan al desplazarte hacia arriba.

<List
  each={messages()}
  inverted
  estimatedItemSize={44}
  style={{ flex: 1 }}
  contentStyle={{ padding: 12, gap: 6 }}
  keyboardDismissMode="interactive"
  onLoadMore={loadOlder}
  loadMoreThreshold={0.5}
>
  {(m) => (
    <View style={{ alignSelf: m().mine ? "flex-end" : "flex-start", maxWidth: "75%", padding: 10, borderRadius: 14, backgroundColor: m().mine ? "#6366f1" : "#e2e8f0" }}>
      <Text style={{ color: m().mine ? "#fff" : "#0f172a" }}>{m().text}</Text>
    </View>
  )}
</List>

Pull to refresh:

const refreshing = signal(false);
const refresh = async () => {
  refreshing.set(true);
  items.set(await load());
  refreshing.set(false);
};

<List each={items()} refreshing={refreshing()} onRefresh={refresh} style={{ flex: 1 }}>
  {(item) => <Text style={{ padding: 16 }}>{item().title}</Text>}
</List>

#ListItemsProps

type ListItemsProps<T> = Pick<ListProps<T>,
  "each" | "children" | "keyExtractor" | "stickyHeaderIndices" | "initialScrollIndex"
  | "onViewableItemsChange" | "viewabilityConfig" | "refreshing" | "onRefresh"
  | "onLoadMore" | "loadMoreThreshold"
  | "header" | "footer" | "empty">;

La mitad de datos y filas de ListProps: lo que pasas a un componente propio que dispone una lista por sí mismo, como una lista de ajustes que envuelve List con su propio padding y divisores.