React Prerendered Component

🤔Partial hydration and caching in a pre-suspense era
Alternatives To React Prerendered Component
Project NameStarsDownloadsRepos Using ThisPackages Using ThisMost Recent CommitTotal ReleasesLatest ReleaseOpen IssuesLicenseLanguage
Js Stack From Scratch19,396
5 months ago1January 19, 201748mitJavaScript
🛠️⚡ Step-by-step tutorial to build a modern JavaScript stack.
Ice17,4987212 days ago84August 26, 2022266mitTypeScript
🚀 ice.js: The Progressive App Framework Based On React(基于 React 的渐进式应用框架)
React Loadable16,5073,2501,0055 months ago30August 09, 201838mitJavaScript
:hourglass_flowing_sand: A higher order component for loading components with promises.
Evergreen12,07175873 days ago246July 18, 202254mitJavaScript
🌲 Evergreen React UI Framework by Segment
Awesome Nextjs8,436
2 days ago62
:notebook_with_decorative_cover: :books: A curated list of awesome resources : books, videos, articles about using Next.js (A minimalistic framework for universal server-rendered React applications)
React I18next8,0641,3071,90417 days ago269September 09, 202218mitJavaScript
Internationalization for react done right. Using the i18next i18n ecosystem.
Dioxus7,96516a day ago12May 03, 2022116apache-2.0Rust
Friendly React-like GUI library for desktop, web, mobile, and more.
Rax7,87011835520 days ago134June 09, 202269otherJavaScript
🐰 Rax is a progressive framework for building universal application.
Loadable Components7,16751137412 days ago29December 12, 202121mitJavaScript
The recommended Code Splitting library for React ✂️✨
React Apollo6,9006,5111,0743 years ago222April 14, 2020202mitJavaScript
:recycle: React integration for Apollo Client
Alternatives To React Prerendered Component
Select To Compare

Alternative Project Comparisons

React Prerendered Component

Partial Hydration and Component-Level Caching


In short: dont try to run js code, and produce a react tree matching pre-rendered one, but use pre-rendered html until js code will be ready to replace it. Make it live.

What else could be done on HTML level? Caching, templatization, and other good things to 🚀, just in a 3kb*.

Prerendered component

Render something on server, and use it as HTML on the client

  • Server side render data
    • call thisIsServer somewhere, to setup enviroment.
    • React-prerendered-component will leave trails, wrapping each block with div with known id.
  • Hydrate the client side
    • React-prerendered-component will search for known ids, and read rendered HTML back from a page.
  • You site is ready!
    • React-prerendered-components are ready. They are rendering a pre-existing HTML you send from a server.
  • Once any component ready to be replaced - hydrate
    • But not before. That's the point - partial hydration, step by step

Bonus - you can store and restore component state.

More details -


  1. Restore data from HTML
  // restore - access DIV and get "counter" from HTML
  restore={(el) => this.setState({counter: +el.querySelector('i').innerHTML})}
  // once we read anything - go live!
  <p>Am I alive?</p>

Is components HTML was not generated during SSR, and it would be not present in the page code - component will go live automatically, unless strict prop is set.

  1. To do a partial hydrating

You may keep some pieces of your code as "raw HTML" until needed. This needed includes:

  • code splitting. You may decrease time to _First Meaningful Paint code splitting JS code needed by some blocks, keeping those blocks visible. Later, after js-chunk loaded, it will rehydrate existing HTML.
  • deferring content below the fold. The same code splitting, where loading if component might be triggered using interception observer.

If your code splitting library (not React.lazy) supports "preload" - you may use it to control code splitting

const AsyncLoadedComponent = loadable(() => import('./deferredComponent'));
const AsyncLoadedComponent = imported(() => import('./deferredComponent'));

  live={AsyncLoadedComponent.preload()} // once Promise resolved - component will go live  
  <AsyncLoadedComponent />
  1. Restore state from JSON stored among.
  // restore - access DIV and get "counter" from HTML
  restore={(_,state) => this.setState(state)}
  store={ this.state }
  // once we read anything - go live!
  <p>Am I alive?</p>

This is not SSR friendly unless....

Wrap your application with PrerenderedControler. This would provide context for all nested components, and "scope" counters used to represent nodes.

This is more Server Side requirement.

import {PrerenderedControler} from 'react-prerendered-component';

ReactDOM.renderToString(<PrerenderedControler><App /></PrerenderedControler>);


Without PrerenderedControler SSR will always produce an unique HTML, you will be not able to match on Client Side.


Client side-only components

It could be a case - some components should live only client-side, and completely skipped during SSR.

import {render} from 'react-dom';
import { ClientSideComponent } from "react-prerendered-component";

const controller = cacheControler(cache);

const result = render(
     Will be rendered only on client

const result = hydrate(
  <PrerenderedControler hydrated>
         Will be rendered only on client __AFTER__ hydrate
  • There is the same component for ServerSideComponents
  • There are hoc version for both cases
import {clientSideComponent} from 'react-prerendered-component';

export default clientSideComponent(MyComponent);

Safe SSR-friendly code splitting

Partial rehydration could benefit not only SSR-enhanced applications, but provide a better experience for simple code splitting.

In the case of SSR it's quite important, and quite hard, to load all the used chunks before triggering hydrate method, or some unloaded parts would be replaced by "Loaders".

Preloaded could help here, if your code-splitting library support preloading, even if it does not support SSR.

import imported from 'react-imported-component';
import {PrerenderedComponent} from "react-prerendered-component";

const AsyncComponent = imported(() => import('./myComponent.js'));

  // component will "go live" when chunk loading would be done
  // until component is not "live" prerendered HTML code would be used
  // that's why you need to `preload`

Yet again - it works with any library which could preload, which is literally any library except React.lazy.


Prerendered component could also work as a component-level cache. Component caching is completely safe, compatible with any React version, but - absolutely synchronous, thus no Memcache or Redis are possible.

import {renderToString, renderToNodeStream} from 'react-dom/server';
import {
} from "react-prerendered-component";

const controller = cacheControler(cache);

const result = renderToString(
  <PrerenderedControler control={control}>
     <CachedLocation cacheKey="the-key">
        any content

// DO NOT USE result! It contains some system information  
result === <x-cachedRANDOM_SEED-store-1>any content</x-cachedRANDOM_SEED-store-1>

// actual caching performed in another place
const theRealResult = cacheRenderedToString(result);

theRealResult  === "any content";

// Better use streams
  <PrerenderedControler control={control}>
     <CachedLocation cacheKey="the-key">
        any content
.pipe(createCacheStream(control)) // magic here

Stream API is completely stream and would not delay Time-To-First-Byte

  • PrerenderedControler - top level controller for a cache. Requires controler to be set
  • CachedLocation - location to be cached.
    • cacheKey - string - they key

    • ttl - number - time to live

    • refresh - boolean - flag to ignore cache

    • clientCache - boolean - flag to enable cache on clientSide (disabled by default)

    • noChange - boolean - disables cache at all

    • variables - object - varibles to use in templatization

    • as=span - string, used only for client-side cache to define a wrapper tag

    • className - string, used only for client-side cache

    • rehydrate - boolean, used only for client-side cache, false values would keep content as a dead html.

  • Placeholder - a template value
    • name - a variable name
  • WithPlaceholder - renderprop version of Placeholder
  • NotCacheable - mark location as non-cacheable, preventing memoization
  • cacheControler(cache) - a cache controller factor, requires object with cache interface to work.
    • cache interface is { get(key): string, set(key, ttl):void }
    • cache implimentation is NOT provided by this library.

Placeholder and Templatization

To optimize rendering performance and reduce memory usage you might use cache templates:

import {CachedLocation, Placeholder, WidthPlaceholder} from 'react-prerendered-component';

const Component = () => (
  <CachedLocation key="myKey" variabes={{name: "GitHub", secret: 42 }}>
    the <Placeholder name="name"/>`s secret is <Placeholder name="secret"/>
    // it's easy to use placeholders in a plain HTML 
    { placeholder => (
       <img src="./img.jpg" alt={placeholder("name") + placeholder("secret")}/>
       // but to use it in "string" attribures you have to use render props


Sometimes you might got something, which is not cacheable. Sometimes cos you better not cache like - like personal information. Sometimes cos it reads data from variable sources and could not be "just cached". It is always hard to manage it. So - just dont cache. It's a one line fix.

import {NotCacheable, notCacheable} from 'react-prerendered-component';

const SafeCache = () => (
    <YourComponent />

const SafeComponent = notCacheable(YourComponent);

Sharing cache between multiple process

Any network based caches are not supported, the best cache you can use - LRU, is bound to single process, while you probably want multi-threaded(workers) rendering, but dont want to maintain per-instance cache.

You may use nodejs shared-memory libraries (not supported by nodejs itself), like:

Cache speed

Results from rendering a single page 1000 times. All tests executed twice to mitigate possible v8 optimizations.

dry      1013 - dry render to kick off HOT
base     868  - the __real__ rendering speed, about 1.1ms per page
cache    805  - with `cacheRenderedToString` used on uncachable appp
cache    801  - second run (probably this is the "real" speed)
partial  889  - with `cacheRenderedToString` used lightly cached app (the cost of caching)
partial  876  - second run
half     169  - page content cached
half     153  - second run
full     22   - full page caching
full     19   - second run
  • full page cache is 42x faster. 0.02ms per page render
  • half page render is 5x faster.
  • partial page render is 1.1x slower.

Prerendered support

It is safe to have prerendered component inside a cached location.

Additional API

  1. ServerSideComponent - component to be rendered only on server. Basically this is PrerenderedComponent with live=false
  2. ClientSideComponent - component to be rendered only on client. Some things are not subject for SSR. ClientSideComponent would not be initially rendered with hydrated prop enabled
  3. thisIsServer(flag) - override server/client flag
  4. isThisServer() - get current environment.

Automatically goes live

Prerendered component is work only once. Once it mounted for a first time.

Next time another UID will be generated, and it will not find component to match. If prerendered-component could not find corresponding component - it goes live automatically.


Idea about PrerenderedComponent is to render something, and rehydrate it back. You should be able to render the same, using rehydrated data.

  • render
  • restore
  • render
  • compare. If result is equal - you did it right.

While area is not "live" - it's dead

Until component go live - it's dead HTML code. You may be make it more alive by transforming HTML to React, using html-to-react, and go live in a few steps.

Size 🤯

Is this package 25kb? What are you thinking about?

  • no, this package is just 3kb or less - tree shaking is great (but not in a dev mode) It is bigger only on server.

See also

react-progressive-hydration - Google IO19 demo is quite similar to react-prerendered-component, but has a few differences.

  • does not use stable uids, utilizing __html:'' + sCU hack to prevent HTML update
  • uses React.hydrate to make component live, breaking connectivity between React Trees
  • while it has some benefits (no real HTML update), it might not be production ready right now



Popular Reactjs Projects
Popular Server Side Rendering Projects
Popular Web User Interface Categories
Related Searches

Get A Weekly Email With Trending Projects For These Categories
No Spam. Unsubscribe easily at any time.
Server Side Rendering
Code Splitting