Questa pagina è stata tradotta automaticamente e può contenere errori. Leggi l'originale in inglese

API

List

nsh esporta List: una lista virtualizzata basata su una scroll view nativa. Esistono solo le righe vicine alla viewport e le loro celle vengono riutilizzate durante lo scorrimento. Quali righe esistono, dove si trovano, le colonne, gli header sticky e la visibilità sono tutti calcolati in modo nativo, quindi lo scorrimento di una lista di diecimila elementi non esegue alcun JS, tranne i binding delle righe che cambiano quando una cella viene riutilizzata.

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

Consulta Liste per la guida e <List> per le props dell’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);

#Le righe vengono riciclate

children è una funzione che renderizza una cella. Viene eseguita una volta per cella, non una volta per elemento: quando una cella esce dalla vista viene riutilizzata per un altro elemento, e item() e index() (entrambi accessor) cambiano. Leggili all’interno di espressioni JSX ({item().name}) in modo che la cella si aggiorni quando viene riutilizzata.

#Props

ListProps<T> combina le props proprie della lista con le props di scorrimento condivise con <Scroll> e le props accettate da ogni elemento, che vengono passate alla scroll view della lista.

#Dati e rendering

PropTipoPredefinitoDescrizione
eachreadonly T[](obbligatorio)Gli elementi. Passa il valore di un signal (each={items()}) per seguirne i cambiamenti; l’inserimento di elementi sopra le righe visibili mantiene quelle righe al loro posto.
children(item: () => T, index: () => number) => JSX.Element(obbligatorio)Renderizza una riga (vedi sopra).
estimatedItemSizenumber50La dimensione delle righe non ancora misurate, in punti, lungo l’asse della lista. Stime vicine al valore reale rendono più accurati l’indicatore di scorrimento e scrollToIndex.
numColumnsnumber1Elementi per riga (liste verticali): una griglia.
horizontalbooleanfalseScorre in orizzontale.
invertedbooleanfalseDispone gli elementi a partire dalla fine, con l’elemento 0 per ultimo (stile chat); parte scorsa fino alla fine e mantiene la distanza dalla fine quando il contenuto cambia.
stickyHeaderIndicesnumber[]Elementi che restano fissati all’inizio dopo essere stati superati con lo scorrimento (una colonna, non invertita).
headerListSlotRenderizzato prima degli elementi.
footerListSlotRenderizzato dopo gli elementi.
emptyListSlotMostrato al posto degli elementi quando each è vuoto.
separatorListSlotRenderizzato tra gli elementi (una colonna).
keyExtractor(item: T, index: number) => stringitem.key, item.id o l’indiceLa chiave di un elemento nei token di visibilità.
initialScrollIndexnumberScorre fino a questo elemento prima del primo frame.
contentStyleListContentStylePadding e spaziature del contenuto: padding, paddingHorizontal, paddingVertical, paddingTop, paddingRight, paddingBottom, paddingLeft, gap, rowGap, columnGap (numeri).
contentClassstringPadding e spaziature del contenuto come classi (p-*, gap-*); contentStyle ha la precedenza su di esse.
styleStyleProp<ViewStyle>Lo stile della lista stessa (assegnale una dimensione: flex: 1 o un’altezza).
testIDstringL’id con cui i test UI trovano la scroll view della lista (nsh test di id:, XCUITest, UI Automator).
refListRef | ((node: ListRef) => void)Vedi metodi del ref.

ListSlot è un componente (Header) oppure un elemento (<Header />).

#Caricamento, aggiornamento e visibilità

PropTipoPredefinitoDescrizione
onLoadMore() => voidChiamata quando la fine si trova entro loadMoreThreshold viewport: carica altri elementi.
loadMoreThresholdnumber1Quanto vicino alla fine (in lunghezze di viewport) scatta onLoadMore.
onLoadMoreAtStart() => voidChiamata quando l’inizio si trova entro loadMoreAtStartThreshold viewport dopo che l’utente o un comando di scorrimento ha spostato la lista: carica ciò che viene prima del primo elemento.
loadMoreAtStartThresholdnumber1Quanto vicino all’inizio (in lunghezze di viewport) scatta onLoadMoreAtStart.
refreshingbooleanLo spinner del pull-to-refresh è visibile.
onRefresh() => voidAbilita il pull to refresh; imposta refreshing mentre carichi.
refreshIndicator{ height: number }L’app disegna un proprio indicatore di pull-to-refresh, alto height, al posto dello spinner.
pullValueAnimatedValueRiceve di quanto la lista viene trascinata oltre il suo bordo superiore, per quell’indicatore.
onViewableItemsChange(info: { viewableItems: ViewToken<T>[]; changed: ViewToken<T>[] }) => voidElementi che sono diventati visibili o hanno smesso di esserlo.
viewabilityConfigViewabilityConfigQuando un elemento viene considerato visibile.
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;
}

#Scorrimento

PropTipoPredefinitoDescrizione
scrollbarboolean | ScrollbarThemetrueL’indicatore di scorrimento è visibile: quello della piattaforma o la barra integrata dell’app; un oggetto è un tema della view stessa.
scrollablebooleantrueL’utente può scorrerla.
bouncesbooleantrueOverscroll oltre i bordi.
pagingEnabledbooleanfalseSi ferma a multipli della viewport.
snapToIntervalnumber0Si ferma a multipli di questa lunghezza (0: disattivato).
snapToOffsetsnumber[]Si ferma a questi offset.
snapToAlignment"start" | "center" | "end""start"Quale punto di un elemento si allinea alla viewport con snapToInterval.
disableIntervalMomentumbooleanfalseUn fling si sposta al massimo di un punto di snap.
decelerationRate"normal" | "fast" | numberpiattaformaQuanto velocemente rallenta un fling (0.998 / 0.99, oppure la velocità mantenuta per millisecondo).
contentInsetPartial<Edges>Spazio attorno al contenuto.
contentOffset{ x?, y? }Dove inizia.
keyboardShouldPersistTaps"never" | "always" | "handled" | boolean"never"Indica se un tap chiude la tastiera ("never": il tap la chiude soltanto).
keyboardDismissMode"none" | "on-drag" | "interactive""none"Indica se il trascinamento chiude la tastiera.
scrollEventThrottlenumberMillisecondi minimi tra gli eventi onScroll (comunque al massimo uno per frame).
scrollValueAnimatedValueUn valore animato alimentato con l’offset di scorrimento (asse principale) sul thread UI, per effetti legati allo scorrimento.

#Eventi di scorrimento

EventoPayloadQuando
onScrollScrollEvent: { offset, contentSize, size, zoomScale }Durante lo scorrimento.
onScrollDragStart{ offset }Inizia un trascinamento.
onScrollDragEnd{ offset }Il dito si solleva.
onMomentumStart{ offset }Inizia uno scorrimento inerziale dopo il trascinamento.
onMomentumEnd{ offset }Lo scorrimento inerziale termina (anche quando un nuovo trascinamento lo interrompe).
onScrollEnd{ offset }Lo scorrimento si è fermato.

Le liste accettano anche le props accettate da ogni elemento (props comuni).

#Metodi del ref

Il ref di una lista riceve un ListRef, con questi metodi oltre a quelli di ViewRef:

MetodoDescrizione
scrollToIndex({ index, animated?, viewPosition?, viewOffset? })Porta in vista l’elemento index. viewPosition lo posiziona: 0 all’inizio della viewport (predefinito), 0.5 al centro, 1 alla fine; viewOffset lo sposta ulteriormente. Risolto in modo nativo con le dimensioni delle righe misurate (o stimate).
scrollToOffset({ offset, animated? })Scorre fino a un offset del contenuto lungo l’asse della lista.
scrollToEnd({ animated? })Scorre fino alla fine del contenuto (l’inizio di una lista invertita).
scrollTo({ x?, y?, animated? })Scorre fino 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>

#Esempi

Una chat: il messaggio più recente in basso, i messaggi più vecchi caricati mentre scorri verso l’alto.

<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 metà di ListProps relativa a dati e righe: ciò che passi a un componente tuo che dispone da sé una lista, ad esempio una lista di impostazioni che incapsula List con il proprio padding e i propri divisori.