npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-instant-webview

v0.2.2

Published

Zero-loading WebView pooling for React Native

Readme

CI npm version license

react-native-instant-webview

WebView pooling library for React Native. Keeps WebView instances alive across screen transitions so users never see a loading spinner twice.

How It Works

[WebViewPoolProvider] ─── children (your app)
       |
       └── WebViewSlot[0]  (hidden or positioned)
       └── WebViewSlot[1]
       └── WebViewSlot[2]

[PooledWebView] ─── placeholder View
       |              borrow() → slot moves to placeholder position
       └── unmount → release() → cleanup → idle

WebView instances live at the Provider root with absolute positioning. When a PooledWebView mounts, it borrows an idle instance and positions it over the placeholder using measureInWindow. On unmount, the instance is cleaned up and returned to the pool — the underlying WKWebView/Android WebView is never destroyed.

Why?

| | Normal WebView | PooledWebView | |---|---|---| | First load | ~500-1500ms | ~500-1500ms | | Subsequent loads | ~500-1500ms | ~0ms | | Memory | Created/destroyed each time | Reused from pool | | Screen transitions | Loading spinner every time | Instant content |

Installation

npm install react-native-instant-webview

Peer Dependencies

npm install react react-native react-native-webview

| Dependency | Version | |---|---| | react | >= 18.0.0 | | react-native | >= 0.70.0 | | react-native-webview | >= 13.0.0 |

Quick Start

Wrap your app with WebViewPoolProvider and use PooledWebView as a drop-in replacement for WebView:

import { WebViewPoolProvider, PooledWebView } from 'react-native-instant-webview';

function App() {
  return (
    <WebViewPoolProvider config={{ poolSize: 3 }}>
      <Navigation />
    </WebViewPoolProvider>
  );
}

function DetailScreen({ url }: { url: string }) {
  return (
    <View style={{ flex: 1 }}>
      <PooledWebView
        source={{ uri: url }}
        containerStyle={StyleSheet.absoluteFill}
        onPoolExhausted={() => console.warn('Pool exhausted')}
      />
    </View>
  );
}

When the pool is exhausted, PooledWebView automatically falls back to a regular WebView so the user always sees content.

API

<WebViewPoolProvider>

Wrap your app root. Initializes the pool and renders hidden WebView slots.

<WebViewPoolProvider config={{ poolSize: 3, cleanupOnReturn: true }}>
  <App />
</WebViewPoolProvider>

Config

| Prop | Type | Default | Description | |---|---|---|---| | poolSize | number | 3 | Number of WebView instances to keep in the pool | | cleanupOnReturn | boolean | true | Run cleanup script when returning to pool | | customCleanupScript | string | built-in | Custom JS to run during cleanup | | defaultWebViewProps | Partial<WebViewProps> | — | Default props applied to all pooled WebViews |

<PooledWebView>

Drop-in replacement for <WebView>. Accepts all WebViewProps plus:

| Prop | Type | Description | |---|---|---| | containerStyle | StyleProp<ViewStyle> | Style for the placeholder container | | poolKey | string | Stable identifier for the borrower | | onPoolExhausted | () => void | Called when no idle instances are available | | onBorrowed | (instanceId: string) => void | Called when an instance is borrowed | | onReturned | (instanceId: string) => void | Called when an instance is returned |

<PooledWebView
  source={{ uri: 'https://example.com' }}
  containerStyle={StyleSheet.absoluteFill}
  onLoadEnd={() => setLoading(false)}
  onBorrowed={(id) => console.log('Borrowed:', id)}
  onReturned={(id) => console.log('Returned:', id)}
  onPoolExhausted={() => console.warn('Falling back to regular WebView')}
/>

usePooledWebView()

Imperative hook for manual borrow/release control.

function MyComponent() {
  const { borrow, release, instanceId, webViewRef } = usePooledWebView();

  useEffect(() => {
    const result = borrow();
    if (result) {
      // Use result.webViewRef to interact with the WebView
    }
    return () => release();
  }, []);
}

useWebViewPool()

Access the pool context directly for advanced use cases.

const { state, borrow, release } = useWebViewPool();
console.log(state.availableCount, state.borrowedCount);

Pool Lifecycle

idle ──borrow()──> borrowed ──release()──> cleaning ──done──> idle
                      │                                         │
                      │         WebView stays alive             │
                      └─────────────────────────────────────────┘
  1. idle — Instance is available. WebView is hidden (1x1px at -9999).
  2. borrowed — Instance is positioned over the PooledWebView placeholder.
  3. cleaning — Cleanup script runs (scroll reset, timer cleanup, DOM clear), then returns to idle.

On the first borrow of each slot, the WebView is lazily created to avoid a Fabric crash where didMoveToWindow fires before the source prop is applied.

Example

See example/bare/App.tsx for a full navigation example comparing pooled vs normal WebViews side by side.

Development

npm install
npm run typecheck    # TypeScript check
npm test             # Run tests (20 tests)
npm run build        # Build with react-native-builder-bob

Troubleshooting

Pool exhausted warning

Increase poolSize in your WebViewPoolProvider config, or ensure you're releasing instances properly (e.g., unmounting PooledWebView components).

WebView shows blank content

Check that the source prop is provided. The pool uses blank HTML internally for idle instances.

Layout issues

Ensure the parent View of PooledWebView has explicit dimensions (e.g., flex: 1).

Contributing

See CONTRIBUTING.md for development setup and guidelines.

License

MIT