Skip to content

Commit

Permalink
Change SSR Fixture to use Partial Hydration
Browse files Browse the repository at this point in the history
This requires the enableSuspenseServerRenderer flag to be manually enabled
for the build to work.
  • Loading branch information
sebmarkbage committed Feb 9, 2019
1 parent 6ae914c commit c818d14
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 18 deletions.
47 changes: 37 additions & 10 deletions fixtures/ssr/src/components/App.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@
import React, {Component} from 'react';
import React, {useState, Suspense} from 'react';

import Chrome from './Chrome';
import Page from './Page';

export default class App extends Component {
render() {
return (
<Chrome title="Hello World" assets={this.props.assets}>
function LoadingIndicator({theme}) {
return <div className={theme + '-loading'}>Loading...</div>;
}

function ThemeToggleButton({theme, onChange}) {
let [targetTheme, setTargetTheme] = useState(theme);
function toggleTheme() {
let newTheme = theme === 'light' ? 'dark' : 'light';
// High pri, responsive update.
setTargetTheme(newTheme);
// Perform the actual theme change in a separate update.
setTimeout(() => onChange(newTheme), 0);
}
if (targetTheme !== theme) {
return 'Switching to ' + targetTheme + '...';
}
return (
<button onClick={toggleTheme}>
Switch to {theme === 'light' ? 'Dark' : 'Light'} theme
</button>
);
}

export default function App({assets}) {
let [theme, setTheme] = useState('light');
return (
<Chrome title="Hello World" assets={assets} theme={theme}>
<div>
<h1>Hello World</h1>
<div>
<h1>Hello World</h1>
<Page />
<ThemeToggleButton theme={theme} onChange={setTheme} />
</div>
</Chrome>
);
}
<Suspense fallback={<LoadingIndicator theme={theme} />}>
<Page theme={theme} />
</Suspense>
</div>
</Chrome>
);
}
20 changes: 20 additions & 0 deletions fixtures/ssr/src/components/Chrome.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,23 @@ body {
padding: 0;
font-family: sans-serif;
}

body.light {
background-color: #FFFFFF;
color: #333333;
}

body.dark {
background-color: #000000;
color: #CCCCCC;
}

.light-loading {
background-color: #CCCCCC;
color: #666666;
}

.dark-loading {
background-color: #333333;
color: #999999;
}
2 changes: 1 addition & 1 deletion fixtures/ssr/src/components/Chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default class Chrome extends Component {
<link rel="stylesheet" href={assets['main.css']} />
<title>{this.props.title}</title>
</head>
<body>
<body className={this.props.theme}>
<noscript
dangerouslySetInnerHTML={{
__html: `<b>Enable JavaScript to run this app.</b>`,
Expand Down
8 changes: 8 additions & 0 deletions fixtures/ssr/src/components/Page.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
.bold {
font-weight: bold;
}
.light-box {
background-color: #CCCCCC;
color: #333333;
}
.dark-box {
background-color: #333333;
color: #CCCCCC;
}
36 changes: 31 additions & 5 deletions fixtures/ssr/src/components/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ const autofocusedInputs = [
<input key="1" autoFocus placeholder="Has auto focus" />,
];

let promise = null;
let isResolved = false;

function Suspend({children}) {
// This will suspend the content from rendering but only on the client.
// This is used to demo a slow loading app.
if (typeof window === 'object') {
if (!isResolved) {
if (promise === null) {
promise = new Promise(resolve => {
setTimeout(() => {
isResolved = true;
resolve();
}, 10000);
});
}
throw promise;
}
}
return children;
}

export default class Page extends Component {
state = {active: false};
handleClick = e => {
Expand All @@ -19,11 +41,15 @@ export default class Page extends Component {
</a>
);
return (
<div>
<p suppressHydrationWarning={true}>A random number: {Math.random()}</p>
<p>Autofocus on page load: {autofocusedInputs}</p>
<p>{!this.state.active ? link : 'Thanks!'}</p>
{this.state.active && <p>Autofocus on update: {autofocusedInputs}</p>}
<div className={this.props.theme + '-box'}>
<Suspend>
<p suppressHydrationWarning={true}>
A random number: {Math.random()}
</p>
<p>Autofocus on page load: {autofocusedInputs}</p>
<p>{!this.state.active ? link : 'Thanks!'}</p>
{this.state.active && <p>Autofocus on update: {autofocusedInputs}</p>}
</Suspend>
</div>
);
}
Expand Down
5 changes: 3 additions & 2 deletions fixtures/ssr/src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import {hydrate} from 'react-dom';
import {unstable_createRoot} from 'react-dom';

import App from './components/App';

hydrate(<App assets={window.assetManifest} />, document);
let root = unstable_createRoot(document, {hydrate: true});
root.render(<App assets={window.assetManifest} />);

0 comments on commit c818d14

Please sign in to comment.