Skip to content

Commit 7b9a5f0

Browse files
committed
Add component templatization feature
1 parent 6c68524 commit 7b9a5f0

File tree

4 files changed

+58
-64
lines changed

4 files changed

+58
-64
lines changed

SSRtest/ModifiedReact.js

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,13 +2204,22 @@ var ReactDOMServerRenderer = function () {
22042204
// TODO: type this more strictly:
22052205

22062206

2207-
ReactDOMServerRenderer.prototype.read = function read(bytes, cache) {
2208-
let saveTemplates;
2209-
function restoreProps(template, props, lookup) {
2207+
ReactDOMServerRenderer.prototype.read = function read(bytes, cache) {
2208+
/*
2209+
--- Component caching variables ---
2210+
start: Tracks start index in output string and templatization data for cached components
2211+
saveTemplates: Tracks templatized components so props can be restored in output string
2212+
restoreProps: Restores actual props to a templatized component
2213+
*/
2214+
const start = {};
2215+
let saveTemplates;
2216+
const restoreProps = (template, props, lookup) => {
22102217
return template.replace(/\{\{[0-9]+\}\}/g, match => props[lookup[match]]);
2211-
}
2212-
2213-
const start = {};
2218+
};
2219+
2220+
/*
2221+
--- Begin React 16 source code with addition of component caching logic ---
2222+
*/
22142223
if (this.exhausted) {
22152224
return null;
22162225
}
@@ -2238,67 +2247,67 @@ var ReactDOMServerRenderer = function () {
22382247
{
22392248
setCurrentDebugStack(this.stack);
22402249
}
2241-
// IF THE CHILD HAS A CACHEKEY PROPERTY ON IT
2250+
2251+
/*
2252+
--- Component caching logic ---
2253+
*/
22422254
if(child.props && child.props.cache) {
22432255
let cacheKey;
2244-
let isTemplate;
2245-
if (child.props.templatized) isTemplate = true;
2246-
/* Lookup object for template post-processing where keys are placeholders
2247-
(e.g. {{0}}) and values are templatized prop names */
2248-
let lookup = {};
2256+
let isTemplate = child.props.templatized ? true : false;
2257+
let lookup;
22492258
let modifiedChild;
22502259
let realProps;
22512260

22522261
if (isTemplate) {
2253-
// First, find cache key from templatized props
2254-
// Swap out templatized props in props object with placeholder for use in cache key
2262+
// Generate templatized version of props to generate appropriate cache key
22552263
let cacheProps = Object.assign({}, child.props);
22562264
let templatizedProps = child.props.templatized;
2265+
lookup = {};
2266+
22572267
if (typeof templatizedProps === 'string') templatizedProps = [templatizedProps];
2258-
for (let i = 0; i < templatizedProps.length; i++) {
2259-
const placeholder = `{{${i}}}`;
2260-
cacheProps[templatizedProps[i]] = placeholder;
2261-
lookup[placeholder] = templatizedProps[i]; // Move down to next if statement? (Extra work/space if not generating template)
2262-
}
2268+
2269+
// Generate template placeholders and lookup object for referencing prop names from placeholders
2270+
templatizedProps.forEach((templatizedProp, index) => {
2271+
const placeholder = `{{${index}}}`;
2272+
cacheProps[templatizedProp] = placeholder;
2273+
lookup[placeholder] = templatizedProp; // Move down to next if statement? (Extra work/space if not generating template)
2274+
});
2275+
22632276
cacheKey = child.type.name + JSON.stringify(cacheProps);
22642277

2265-
// Check whether the component template is being generated
2278+
// Generate modified child with placeholder props to render template
22662279
if (!start[cacheKey]) {
2267-
// Variables for templatization
22682280
modifiedChild = Object.assign({}, child);
22692281
modifiedChild.props = cacheProps;
22702282
realProps = child.props;
22712283
}
22722284
} else {
2273-
// Not a template
2285+
// Generate cache key for non-templatized component from its name and props
22742286
cacheKey = child.type.name + JSON.stringify(child.props);
22752287
}
22762288

2277-
// IF NOT FOUND IN CACHE
2278-
if (!cache.storage.get(cacheKey)){
2289+
if (!cache.storage.get(cacheKey)) { // Component not found in cache
22792290
let r;
22802291

22812292
// If templatized component and template hasn't been generated, render a template
22822293
if (!start[cacheKey] && isTemplate) {
22832294
r = this.render(modifiedChild, frame.context, frame.domNamespace);
22842295
start[cacheKey] = { startIndex: out.length, realProps, lookup };
22852296
}
2286-
// Otherwise, render as normal with props for simple caching or if template was generated earlier in this render
2297+
// Otherwise, render with actual props
22872298
else r = this.render(child, frame.context, frame.domNamespace);
22882299

2289-
// For simple component caching, bookmark the start index of component in output string
2300+
// For simple (non-template) caching, save start index of component in output string
22902301
if (!isTemplate) start[cacheKey] = out.length;
2291-
// Note: no bookmark needed if template was generated earlier in the same render
2302+
22922303
out += r;
2293-
// IF FOUND IN CACHE
2294-
} else {
2295-
// Cached component found in storage
2304+
} else { // Component found in cache
22962305
let r = cache.storage.get(cacheKey);
22972306
let restoredTemplate;
22982307
if (isTemplate) restoredTemplate = restoreProps(r, realProps, lookup);
22992308
out += restoredTemplate ? restoredTemplate : r;
23002309
}
2301-
} else {
2310+
} else { // Normal rendering for non-cached components
23022311
out += this.render(child, frame.context, frame.domNamespace);
23032312
}
23042313
{
@@ -2307,6 +2316,9 @@ var ReactDOMServerRenderer = function () {
23072316
}
23082317
}
23092318

2319+
/*
2320+
--- After initial render of cacheable components, recover from output string and store in cache ---
2321+
*/
23102322
for (let component in start) {
23112323
let tagStack = [];
23122324
let tagStart;
@@ -2325,7 +2337,7 @@ var ReactDOMServerRenderer = function () {
23252337
else tagStack.pop();
23262338
}
23272339
} while (tagStack.length !== 0);
2328-
// cache component by slicing 'out'
2340+
// Cache component by slicing 'out'
23292341
const cachedComponent = out.slice(componentStart, tagEnd);
23302342
if (typeof start[component] === 'object') {
23312343
if (!saveTemplates) saveTemplates = [];
@@ -2335,27 +2347,21 @@ var ReactDOMServerRenderer = function () {
23352347
cache.storage.set(component, cachedComponent);
23362348
}
23372349

2338-
console.log('HERE IS OUR CURRENT CACHE', cache.storage);
2339-
// RESTORE PROPS FOR ALL TEMPLATIZED COMPONENTS ONLY AFTER CACHING
2350+
// After caching all cacheable components, restore props to templates
23402351
if (saveTemplates) {
23412352
let outCopy = out;
23422353
out = '';
23432354
let bookmark = 0;
23442355
saveTemplates.sort((a, b) => a.startIndex - b.startIndex);
2345-
console.log('SAVED THESE TEMPLATES', saveTemplates)
2346-
for (let i = 0; i < saveTemplates.length; i++) {
2347-
out += outCopy.substring(bookmark, saveTemplates[i].startIndex)
2348-
bookmark = saveTemplates[i].endIndex;
2349-
let restoredTemplate = restoreProps(outCopy.slice(saveTemplates[i].startIndex, saveTemplates[i].endIndex),
2350-
saveTemplates[i].realProps, saveTemplates[i].lookup);
2351-
console.log('RESTORED TEMPLATE', restoredTemplate);
2352-
out += restoredTemplate;
2353-
}
2356+
// Rebuild output string with actual props
2357+
saveTemplates.forEach(savedTemplate => {
2358+
out += outCopy.substring(bookmark, savedTemplate.startIndex)
2359+
bookmark = savedTemplate.endIndex;
2360+
out += restoreProps(outCopy.slice(savedTemplate.startIndex, savedTemplate.endIndex),
2361+
savedTemplate.realProps, savedTemplate.lookup);
2362+
});
23542363
out += outCopy.substring(bookmark, outCopy.length);
23552364
}
2356-
// let restoredTemplate = restoreProps(cachedComponent, start[component].realProps, start[component].lookup);
2357-
// THIS IS NO GOOD. IT MUTATES THE OUTPUT AND CHANGES EVERYTHING SO THE START FOR EVERYTHING IS WAY OFF
2358-
23592365
return out;
23602366
};
23612367

SSRtest/src/shared/App.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ export default class App extends Component {
1717
return (
1818
<div>
1919
<h1>THIS IS AN APP</h1>
20-
21-
<List />
20+
<Button cache />
2221
<BlogPost day="Monday" cache templatized="day" />
2322
<BlogPost day="Tuesday" cache templatized="day" />
24-
<Button cache />
23+
24+
<List />
25+
2526
</div>
2627
);
2728
}

SSRtest/src/shared/List.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default class List extends Component {
1111
render() {
1212
let bunchOfProducts = [];
1313
const templatizedProps = ["name", "description", "price"];
14-
for (let i=0; i<1000; i++) {
14+
for (let i=0; i<100; i++) {
1515
bunchOfProducts.push(<ProductInfo key={i} name={`Thing ${i}`} description="This product is awesome!" price={i * 10} nonTemplatized="THIS TEXT SHOULD NEVER CHANGE" cache templatized={templatizedProps} />);
1616
}
1717
return (

SSRtest/src/shared/ProductInfo.js

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ export default class ProductInfo extends Component {
55
render() {
66
return (
77
<div>
8-
{/* This is a comment */}
98
<p><strong>Product Name: </strong>{this.props.name}</p>
109
<p><strong>Product Description: </strong>{this.props.description}</p>
1110
<p><strong>Price: </strong>${this.props.price}</p>
@@ -14,16 +13,4 @@ export default class ProductInfo extends Component {
1413
</div>
1514
);
1615
}
17-
}
18-
/*
19-
20-
<p>Non-Templatized Prop: {this.props.nonTemplatized}</p>
21-
<hr />
22-
23-
This works:
24-
<p><strong>Product Name: </strong><span>{this.props.name}</span></p>
25-
<p><strong>Product Description: </strong><span>{this.props.description}</span></p>
26-
<p><strong>Price: </strong><span>${this.props.price}</span></p>
27-
<p><strong>Non-Templatized Prop: </strong><span>{this.props.nonTemplatized}</span></p>
28-
<hr />
29-
*/
16+
}

0 commit comments

Comments
 (0)