@charlespeters
<div>
, a single bundle Single page apps have a single point of failure.
Lack SEO.
Suffer Performance Concerns.
Server side rendering your React application
Likely, your client.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
ReactDOM.render(<App />, document.getElementById('root'));
and an index.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SSR</title>
</head>
<body>
<div id="root"></div>
<script src="./client.js"></script>
</body>
</html>
import React from "react";
import { renderToString } from "react-dom/server";
import App from "./components/App";
export default function template(props) {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SSR</title>
</head>
<body>
<div id="root">${renderToString(<App {...props} />)}</div>
<script src="./client.js"></script>
</body>
</html>
`;
}
import express from "express";
import template from "./template";
const app = express();
app.get("/*", (req, res) => {
res.status(200).send(template())
});
app.listen(3000);
// client.js
import React from 'react'
import ReactDOM from "react-dom";
import App from './components/App';
ReactDOM.hydrate(<App />, document.getElementById('root'));
constructor()
, UNSAFE_componentWillMount()
😳setState()
🚫On the client
ReactDOM.hydrate(
<BrowserRouter>
<App />
</BrowserRouter>
)
& on the server
renderToString(
<StaticRouter>
<App />
</StaticRouter>
)
function template({ location, ...props }) {
const context = {}
const app = renderToString(
<StaticRouter location={location} context={context}>
<App {...props} />
</StaticRouter>
)
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SSR</title>
</head>
<body>
<div id="root">${app}</div>
<script src="./client.js"></script>
</body>
</html>
`;
}
app.get("/*", (req, res) => {
const markup = template({ location: req.url })
res.status(200).send(markup)
});
async
/await
async (req, res) => {
const data = await fetch('endpoint/').then(res => res.json())
const markup = renderToString(<App {...data} />)
res.send(markup)
}
class App extends React.Component {
static async getInitialProps() {
const data = await fetch('endpoint/').then(res => res.json())
return { data }
}
}
You can grab your token from the server and call the same endpoint as that user.
async (req, res) => {
const { TOKEN } = req.cookies
const data = await fetch('endpoint/', { headers: { Authorization: TOKEN } }).then(res => res.json())
}
Don't travel alone. 🚀
yarn add react react-dom next
{ "dev": "next" }
pages/index.js
Hooks and Suspense
const ThemeContext = React.createContext({ dark: true });
function App(props) {
const [open, setOpen] = React.useState(false);
const context = React.useContext(ThemeContext);
return (
<div
className="App"
style={{
background: context.dark ? 'black' : 'white',
color: context.dark ? 'white' : 'black'
}}>
<h1>Hello {props.name}</h1>
{open && 'I AM OPEN'}
<button onClick={() => setOpen(!open)}>Toggle</button>
</div>
);
}