Skip to content

Instantly share code, notes, and snippets.

@developit
Last active July 20, 2023 14:21
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save developit/b8c82603cb7994bce430f87f3bfa509f to your computer and use it in GitHub Desktop.
Save developit/b8c82603cb7994bce430f87f3bfa509f to your computer and use it in GitHub Desktop.

Preact: Progressive Hydration

Preact now supports seamless progressive hydration.

Any component can throw during hydration (or new tree creation like a route change!), and if a component somewhere higher in the tree catches that via componentDidCatch, hydration gets paused.

Re-rendering the tree (via setState, etc) simply resumes hydration where it left off.

import { lazy, ErrorBoundary } from './preact-progressive-hydration.js';

const MyLazyComponent = lazy(() => import('./components/some-big-component'));
// ^ async version of `import MyLazyComponent from './components/some-big-component'`

function App() {
  return (
    <div id="app">
      <header>
        Neato: this hydrates and gets interactive while our lazy component loads.
      </header>

      {/* Place this wherever you want hydration to "rewind" to: */}
      <ErrorBoundary>

        <MyLazyComponent cool={true} />
        {/* ^ rendering calls import(), defers hydration until its ready */}

      </ErrorBoundary>
    
    </div>
  );
}

hydrate(<App />, self.root);
import { h } from 'preact';
export function lazy(load) {
let component, promise;
return function Lazy(props) {
if (!promise) promise = load().then(m => component = m.default || m);
if (!this.waiting) this.waiting = promise.then(c => this.setState({c}));
if (!component) throw promise;
return h(component, props);
}
}
export function ErrorBoundary(props) { return props.children; }
ErrorBoundary.prototype.componentDidCatch = function (err) {
if (err && err.then) this.__d = true;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment