Skip to content

Refresh and load more ​

Promise completion ​

tsx
<SmartRefreshLayout
  hasMore={hasMore}
  onRefresh={async () => {
    const page = await api.firstPage();
    setRows(page.rows);
    setHasMore(page.hasMore);
  }}
  onLoadMore={async () => {
    const page = await api.nextPage();
    setRows((rows) => [...rows, ...page.rows]);
    setHasMore(page.hasMore);
    return { hasMore: page.hasMore };
  }}
>
  <FlatList {...listProps} />
</SmartRefreshLayout>

In uncontrolled mode, a fulfilled or rejected Promise finishes the native animation. Rejections also call onRefreshError or onLoadMoreError when provided.

Controlled state ​

Passing refreshing or loadingMore makes that state controlled. Reset the value in every completion path:

tsx
onRefresh={async () => {
  setRefreshing(true);
  try {
    await reload();
  } finally {
    setRefreshing(false);
  }
}}

One request per instance ​

Refresh and pagination share an instance lock. The callback receives a { requestId, source } object, where source is gesture or programmatic. Duplicate gestures, crossed refresh/load requests, and stale delayed finish commands are ignored.

Load-more modes ​

pull is the default and requires a pull-release gesture. auto only unlocks after content exceeds the viewport and the user performs a real upward scroll. Do not combine automatic mode with FlatList.onEndReached.

Instance commands ​

ts
ref.current?.beginRefresh(150);
ref.current?.finishRefresh({ success: true, delay: 200 });
ref.current?.beginLoadMore();
ref.current?.finishLoadMore({ success: true, hasMore: false });
ref.current?.resetNoMoreData();

The boolean begin result reports command acceptance, not request completion.

Released under the MIT License.