Skip to content

HuolalaTech/rn-pull-to-refresh

Repository files navigation

rn-pull-to-refresh

Cross-platform native Pull-to-Refresh for React Native — with New Architecture (Fabric) support

English | 中文

About

This package is a fork and secondary development of the PullToRefresh module from react-native-troika by listenzz.

We kept the proven API and multi-platform native implementation (Android SmartRefreshLayout, iOS MJRefresh, HarmonyOS native layer), and extended it with React Native New Architecture (Fabric) support on Android, iOS, and HarmonyOS — addressing the biggest gap in the upstream 0.x line.

Upstream reference: listenzz/react-native-troika · Original PullToRefresh docs: packages/pull-to-refresh

Why this fork? (Pain points)

Pull-to-refresh is everywhere in mobile apps, but choosing a library in the React Native ecosystem often means painful trade-offs:

Library Platforms Pull + Load more New Architecture (Fabric) Last release
react-native-troika/pull-to-refresh (upstream 0.x) Android · iOS · Harmony ✅ Rich (SmartRefresh on Android) ❌ No Fabric 2025
react-native-MJRefresh iOS · Harmony only Limited 2019
react-native-pull All (pure JS) Partial, known issues 2017
react-native-SmartRefreshLayout Android · Harmony only Partial 2019
Gesture / Reanimated–based solutions All Varies Requires RN ≥ 0.74

The problems we hit in production

  1. No New Architecture on the best cross-platform option
    Upstream react-native-troika 0.x works well on Android, iOS, and Harmony with customizable headers/footers and load-more — but does not support Fabric. Teams enabling the New Architecture cannot use it without forking.

  2. Fabric-ready alternatives force a heavy RN upgrade
    Gesture-based pull-to-refresh stacks typically require React Native 0.74+ and related dependency bumps (react-native-gesture-handler, react-native-reanimated, etc.). Many brownfield apps stay on older RN versions and cannot adopt them quickly.

  3. Fragmented platform coverage
    MJRefresh wrappers often skip Android; SmartRefresh wrappers skip iOS. Maintaining two libraries doubles integration and QA cost.

  4. Stale or unmaintained packages
    Several community libraries have not been updated since 2017–2019, with poor compatibility on modern RN, Gradle, and Xcode toolchains.

  5. Pure JS refresh controls fight native scroll
    JS-only solutions are easier to ship but tend to conflict with nested scrolling, FlatList/ScrollView gestures, and native refresh UX expectations.

What this package offers

  • Same mental model as troikaPullToRefresh, custom PullToRefreshHeader / PullToRefreshFooter, load-more
  • Android · iOS · HarmonyOS in one package
  • Old Architecture + New Architecture (Fabric) — runtime detection and Fabric-native components where enabled

Features

  • Native pull-to-refresh and load-more (footer)
  • Fully customizable refresh header and footer in React
  • Refresh state and offset events for custom animations
  • Android: SmartRefreshLayout
  • iOS: MJRefresh
  • HarmonyOS: native C++ Fabric integration
  • Optional RefreshControl-style wrapper for Android

Version compatibility

Version RN version Architecture
0.x >= 0.67 Legacy (Paper)
1.x (WIP) >= 0.76 New Architecture (Fabric)
RN version Notes
0.72+ Baseline for legacy arch usage
0.76+ Recommended when enabling Fabric / 1.x line

Installation

yarn add rn-pull-to-refresh
# or
npm install rn-pull-to-refresh

iOS

cd ios && pod install

MJRefresh is declared in RNPullToRefresh.podspec.

Android

Auto-linked via React Native autolinking. Uses SmartRefreshLayout on the native side.

HarmonyOS

Include the harmony/library module in your OpenHarmony / RNOH project per your monorepo conventions.

Quick start

import React, {useState, useCallback} from 'react';
import {FlatList, Text} from 'react-native';
import {PullToRefresh} from 'rn-pull-to-refresh';

export function ListScreen() {
  const [refreshing, setRefreshing] = useState(false);
  const [data, setData] = useState<string[]>([]);

  const onRefresh = useCallback(async () => {
    setRefreshing(true);
    await fetchData();
    setRefreshing(false);
  }, []);

  return (
    <PullToRefresh style={{flex: 1}} onRefresh={onRefresh} refreshing={refreshing}>
      <FlatList
        data={data}
        renderItem={({item}) => <Text>{item}</Text>}
        keyExtractor={(_, i) => String(i)}
      />
    </PullToRefresh>
  );
}

Custom header

import {PullToRefresh, PullToRefreshHeader} from 'rn-pull-to-refresh';

function MyHeader(props) {
  return (
    <PullToRefreshHeader {...props}>
      {/* your UI */}
    </PullToRefreshHeader>
  );
}

<PullToRefresh header={<MyHeader onRefresh={onRefresh} refreshing={refreshing} />} ... />

Load more

<PullToRefresh
  onLoadMore={loadMore}
  loadingMore={loadingMore}
  noMoreData={noMoreData}
  ...
/>

Default header / footer

import {PullToRefresh} from 'rn-pull-to-refresh';

PullToRefresh.setDefaultHeader(MyHeader);
PullToRefresh.setDefaultFooter(MyFooter);

API overview

Export Description
PullToRefresh Container wrapping scrollable children
PullToRefreshHeader Native header slot for custom UI
PullToRefreshFooter Native footer slot (load more)
RefreshControl Android-friendly helper aligned with RN RefreshControl props

See src/types.ts for PullToRefreshProps, state constants (PullToRefreshStateIdle, etc.), and event types.

Preview

Pull to refresh demo

License

MIT — see LICENSE.

Derived from react-native-troika (MIT). Please retain attribution when redistributing.

About

pull-to-refresh component for rn

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors