Skip to content

Commit c818d14

Browse files
committed
Change SSR Fixture to use Partial Hydration
This requires the enableSuspenseServerRenderer flag to be manually enabled for the build to work.
1 parent 6ae914c commit c818d14

File tree

6 files changed

+100
-18
lines changed

6 files changed

+100
-18
lines changed

fixtures/ssr/src/components/App.js

+37-10
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,44 @@
1-
import React, {Component} from 'react';
1+
import React, {useState, Suspense} from 'react';
22

33
import Chrome from './Chrome';
44
import Page from './Page';
55

6-
export default class App extends Component {
7-
render() {
8-
return (
9-
<Chrome title="Hello World" assets={this.props.assets}>
6+
function LoadingIndicator({theme}) {
7+
return <div className={theme + '-loading'}>Loading...</div>;
8+
}
9+
10+
function ThemeToggleButton({theme, onChange}) {
11+
let [targetTheme, setTargetTheme] = useState(theme);
12+
function toggleTheme() {
13+
let newTheme = theme === 'light' ? 'dark' : 'light';
14+
// High pri, responsive update.
15+
setTargetTheme(newTheme);
16+
// Perform the actual theme change in a separate update.
17+
setTimeout(() => onChange(newTheme), 0);
18+
}
19+
if (targetTheme !== theme) {
20+
return 'Switching to ' + targetTheme + '...';
21+
}
22+
return (
23+
<button onClick={toggleTheme}>
24+
Switch to {theme === 'light' ? 'Dark' : 'Light'} theme
25+
</button>
26+
);
27+
}
28+
29+
export default function App({assets}) {
30+
let [theme, setTheme] = useState('light');
31+
return (
32+
<Chrome title="Hello World" assets={assets} theme={theme}>
33+
<div>
34+
<h1>Hello World</h1>
1035
<div>
11-
<h1>Hello World</h1>
12-
<Page />
36+
<ThemeToggleButton theme={theme} onChange={setTheme} />
1337
</div>
14-
</Chrome>
15-
);
16-
}
38+
<Suspense fallback={<LoadingIndicator theme={theme} />}>
39+
<Page theme={theme} />
40+
</Suspense>
41+
</div>
42+
</Chrome>
43+
);
1744
}

fixtures/ssr/src/components/Chrome.css

+20
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,23 @@ body {
33
padding: 0;
44
font-family: sans-serif;
55
}
6+
7+
body.light {
8+
background-color: #FFFFFF;
9+
color: #333333;
10+
}
11+
12+
body.dark {
13+
background-color: #000000;
14+
color: #CCCCCC;
15+
}
16+
17+
.light-loading {
18+
background-color: #CCCCCC;
19+
color: #666666;
20+
}
21+
22+
.dark-loading {
23+
background-color: #333333;
24+
color: #999999;
25+
}

fixtures/ssr/src/components/Chrome.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default class Chrome extends Component {
1414
<link rel="stylesheet" href={assets['main.css']} />
1515
<title>{this.props.title}</title>
1616
</head>
17-
<body>
17+
<body className={this.props.theme}>
1818
<noscript
1919
dangerouslySetInnerHTML={{
2020
__html: `<b>Enable JavaScript to run this app.</b>`,

fixtures/ssr/src/components/Page.css

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
.bold {
22
font-weight: bold;
33
}
4+
.light-box {
5+
background-color: #CCCCCC;
6+
color: #333333;
7+
}
8+
.dark-box {
9+
background-color: #333333;
10+
color: #CCCCCC;
11+
}

fixtures/ssr/src/components/Page.js

+31-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,28 @@ const autofocusedInputs = [
77
<input key="1" autoFocus placeholder="Has auto focus" />,
88
];
99

10+
let promise = null;
11+
let isResolved = false;
12+
13+
function Suspend({children}) {
14+
// This will suspend the content from rendering but only on the client.
15+
// This is used to demo a slow loading app.
16+
if (typeof window === 'object') {
17+
if (!isResolved) {
18+
if (promise === null) {
19+
promise = new Promise(resolve => {
20+
setTimeout(() => {
21+
isResolved = true;
22+
resolve();
23+
}, 10000);
24+
});
25+
}
26+
throw promise;
27+
}
28+
}
29+
return children;
30+
}
31+
1032
export default class Page extends Component {
1133
state = {active: false};
1234
handleClick = e => {
@@ -19,11 +41,15 @@ export default class Page extends Component {
1941
</a>
2042
);
2143
return (
22-
<div>
23-
<p suppressHydrationWarning={true}>A random number: {Math.random()}</p>
24-
<p>Autofocus on page load: {autofocusedInputs}</p>
25-
<p>{!this.state.active ? link : 'Thanks!'}</p>
26-
{this.state.active && <p>Autofocus on update: {autofocusedInputs}</p>}
44+
<div className={this.props.theme + '-box'}>
45+
<Suspend>
46+
<p suppressHydrationWarning={true}>
47+
A random number: {Math.random()}
48+
</p>
49+
<p>Autofocus on page load: {autofocusedInputs}</p>
50+
<p>{!this.state.active ? link : 'Thanks!'}</p>
51+
{this.state.active && <p>Autofocus on update: {autofocusedInputs}</p>}
52+
</Suspend>
2753
</div>
2854
);
2955
}

fixtures/ssr/src/index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
2-
import {hydrate} from 'react-dom';
2+
import {unstable_createRoot} from 'react-dom';
33

44
import App from './components/App';
55

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

0 commit comments

Comments
 (0)