🧠 A New React and the Old Cache
Tags: react, cache, ssr
Published: 2019-04-03 12:07:35

---
title: 🧠 A New React and the Old Cache
published: true
description: Have you ever tried to cache something in React? Just to make it faster?
tags: react, cache, SSR
cover_image: https://thepracticaldev.s3.amazonaws.com/i/bwmrd03jd68yop9gxhff.jpeg
series: A split second later 
---
Is React 🚀 FAST, or React is 🐌 SLOW? It's super easy to answer this question, just a no brainer.

- React is fast. Full stop. React is fast when it could be fast: not displaying too much data, and not animating something in 60 frames per second. There is always a _faster_ kid on the block(Svelte?), but React is fast enough almost for any case.
- React is slow. Another full stop. It's not a big deal to make it slow - inline 1000 SVGs and use React to render them all, or render 100 pages simultaneously on a Server Side.

In short - React is 👍 as a Client Side Library, but for Server Side Rendering - oh, it will 🔥 burn your CPU, and AWS bill. Not because it slow, but because everything has limits.

That's obvious - you cannot compare situations when ALL CPUs are working for a ONE customer sake (in browser), and the situating, when you have to render the same, but for a dozen clients simultaneously.

That's also obvious how to mitigate the problem - it was know for generation, and for react itself it’s the main idea around handling unneeded updates - memoization. Or, in terms of old school SSR - just __cache__. 
Cache for small blocks, cache for big blocks, cache for pages, data and intermediate results. Cache as much as possible, and let render results of a one customer speed up render for another customer.

> Caching is a well-known pattern, and always was saving a day! For decades! For everyone! Except for React.

### React days

So, caching in React? Do you remember an API for it? No, you don’t. There isn’t any.

You still able to cache `renderToString` result - not a big deal, or [cache `renderToNodeStream`](https://zeit.co/blog/streaming-server-rendering-at-spectrum) as __mxstbr__ did for Spectrum last year.

But do we need caching? 

Yes - React 15 was REALLY SLOW, and React 16, even if it is much faster, still require some time to render the result.
Anything requires some time. Everything has requirements and limits.

## Caching in React
As long as the problem existed, there were many devs, with a _caching background_(from previous experiences in different frameworks or languages) to solve it -  new patterns and libraries emerged.

#### Rapscallion
Alternative to React-DOM. Our hero. Saved millions of CPU cycles. Was able to handle data loading on the component level, and caching the result as well.

Worked perfectly. __Till React 16__. Not worked after.
{% github FormidableLabs/rapscallion %}

####
Another great tool for Component Level caching. Another tool which hacks into React and trying change the way it works. Yet another tool which __does not works​ with React 16__.
{% github electrode-io/electrode-react-ssr-caching %}

#### react-ssr-optimization
A magic system for _memoization_ and _templatenization_ from Walmart Labs. Was once broken during React 14-15 migration, and __didn't get React 16__ support.
{% github walmartlabs/react-ssr-optimization %}

#### React-component-caching
TLDR: Actually a __working__ one!
{% github rookLab/react-component-caching %}

Citing [Speedier Server-Side Rendering in React 16 with Component Caching](https://medium.com/@reactcomponentcaching/speedier-server-side-rendering-in-react-16-with-component-caching-e8aa677929b1)
> Sasha Aickin [introduced and demoed component caching](https://youtu.be/PnpfGy7q96U?t=22m35s) in a 2016 talk on ways to speed up server-side rendering. Soon afterwards, Walmart Labs created a [component caching library](https://github.com/electrode-io/electrode-react-ssr-caching) with a profiling feature to time renders. The idea received attention at [React Amsterdam](https://youtu.be/4TOi9l6x-jo) last year, and it has surfaced in discussions on Github. A component caching API was also incorporated in Formidable’s React server renderer, [Rapscallion](https://github.com/FormidableLabs/rapscallion).
With the release of React 16 last September, many of these efforts have been due for a reboot. React has improved the speed of its server-side rendering methods and now offers two streaming methods. We were curious if it was possible to harness the power of component caching with these new and improved methods. So we built [React Component Caching](https://github.com/rookLab/react-component-caching) to give developers the ability to do just that.

-----

But, you know, this library is quite complex inside, and would be broken on next React release - 100%. And user-facing API is also quite complex... But it's working, working with memcache or other caching libraries and was a single saviour... until today.

## React-Prerendered-Component
Then - let me introduce another approach to a component level caching in React, which will __never be broken__. Never by design.

```js
import {CachedLocation, NotCacheable} from 'react-prerendred-component';

const MyCachedComponent = () => (
  <CachedLocation cacheKey="MyCachedComponent">
    any code you want
  </CachedLocation>
);

// component like this shall not be cached.
const SomeNonPureImportantComponent = () => (
 <NotCacheable>hey {global.userName}</NotCacheable>
);
```

Simple? Easy? How does it work?

#### How it works
1. `CachedLocation` will wrap your component with `<x-cached-store>{children}<x-cached-store>`
2. result of `renderToString` would be analyzed for such markers, and marker's content would be moved into the cache. For `renderToStream` the same is working via `transform streams`.
3. if `key` was present in the store, then `CachedLocation` would render `<x-cached-restore-key />`, and the same post-filter would replace this text by the stored value.

This works on HTML/stream transformation level, and __don't rely on ANY React internals__.

The same is __working for Client Side__! `CachedLocation` will just wrap your data with a `div` and store/restore data using `dangerouslySetInnerHTML`. For example, you might _cache_ those big SVGs, I was mentioning in the beginning.

```js
<CachedLocation cacheKey="svg-fileName">
  // react component first time, just a string second.
  <MySVRGComponent />
</CachedLocation>

renderToString(...);

// - first render, cache is empty, making a full render
// <x-cached-store-1><svg..../></x-cached-store-1>
// - cache stored, extra tags removed
// <svg .../> 

renderToString(...);

// - second render, cache exists - restore entity
// <x-cached-restore-1/>
// - we know what to restore
// <svg ...
```
> While `CachedLocation` is adding extra tags during the render - they would be removed later. It's a transparent process!

It is all __pure HTML based__ solution, which works _after_ React did the job.

#### XSS my friend?
So - let's recall it once again - `CachedLocation` will put some `tag` in result HTML and some dummy(it is) RegEx will do the rest.

What if your dear customer will do the same? What if the same `tag` would be found in JSON, script and visa versa? Of course, __it will blow__ :P

So - in the real world this library would not use so obvious tag names, but will use [nanoid](https://github.com/ai/nanoid) to generate unique tag names every render. So - no XSS and no false positives are possible, relax.

```js
<x-cached-supersecretstring-11 /> // it's "safe"
```
The only, hm, problem here - now caches, generated in different threads, are not compatible with each other, and so in case of distributed cache you have to specify `super-secret-seed` by your own.

#### Templatezation
It's a long, and probably not quite a correct, term stand for less _variative_ memoization.

For example - header of `dev.to` contains your avatar, but everything else is the same - you may "template it" into the static and cached `<Header/>`. What would happen if you will cache header in a per-user basis? Well, cache is not infinite.

![](https://arkwright.github.io/images/scaling-react-server-side-rendering/cache-explosion.svg)
> Picture from [Scaling React Server-Side Rendering](https://arkwright.github.io/scaling-react-server-side-rendering.html).

Instead of having 100500 different `<Button>unuqieText</Button>` you might just have `<Button>#text#</Button>` - so you will memoize only complex html markup, adding some "variables" using simple `replace` methods.

While using _string replaces_ is not quite safe, this library gives you a few components to _inject_ Placeholders, which uses Context API to drill down the props, and requires just a small code style changes to be used.
```js
const UserHeader = () => (
 <div>
   .....
   <Placeholder name="userName"/>
   ....
 </div>
)

renderToString(<CacheLocation variables={{userName:'Joe'}}><UserHeader/></CacheLocation>);

// <x-cached-store-1 userName="Joe">....{x-cached-placeholder-userName}...</x-cached-store-1>

renderToString(<CacheLocation variables={{userName:'Jack'}}><UserHeader/></CacheLocation>);

// <x-cached-restore-1 userName="Jack"/>
// ....{x-cached-placeholder-userName}...
// ....Jack...
```
This is a very powerful tactic to reduce memory usage and skyrocket your application via __transforming your brand new React App to old school template engine__. 

Which is just 🚀VERY🚀FAST🚀.

PS: This could give you sub-millisecond SSR, `react-component-caching` have proved it.
PPS: But this is not working _yet_ for the client-side cache. Using variables for CSR caching will disable caching.

Another name of this technique is cache `interpolation`, and if you want to TRULY understand everything behind fragment caching - read [The Article](https://arkwright.github.io/scaling-react-server-side-rendering.html).

#### Where is the cache?
Another cool moment this approach is a `cache`. A simple React 16/Suspense compatible cache model.

- synchronously `get` the cache 
- synchronously `set` the cache. 
- No cache available? - Throw a promise!

You cannon use [react-cache](https://github.com/facebook/react/tree/master/packages/react-cache), as long as it utilizes a different model (there is no `set`), but any other cache, including in-memory or __shared-memory__ ones - easy.
> But not memcache, as long as _asynchronius_ cache is not supported.

Prerendered component gives you the power of component `memoization`, and `templatization` both for Server and Client, and would not break in the future, just because it built that way - to never let you down.

Give it a try.
Or just think about it.

{% github theKashey/react-prerendered-component %}

{% twitter 1060432205829201920 %}

PS: By the way, react-prerendered-component was a hero for other article:
{% link https://dev.to/thekashey/react-code-splitting-in2019-3cmg %}