or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-routing.mdhistory.mdhooks.mdindex.mdlocation-context.mdnavigation.mdrouting.mdserver-rendering.mdutilities.md

server-rendering.mddocs/

0

# Server-Side Rendering

1

2

Components and utilities for rendering routes on the server with static location context.

3

4

## Capabilities

5

6

### ServerLocation Component

7

8

Location provider component designed for server-side rendering that provides static location context.

9

10

```javascript { .api }

11

/**

12

* Location provider for server-side rendering with static location context

13

* @param props - Server location configuration

14

*/

15

function ServerLocation(props: {

16

url: string;

17

children: React.ReactNode;

18

}): React.ReactElement;

19

```

20

21

**Props:**

22

- `url` (string, required) - The URL to use as the current location

23

- `children` (React.ReactNode) - Child components that will receive location context

24

25

**Usage Examples:**

26

27

```javascript

28

import React from "react";

29

import { renderToString } from "react-dom/server";

30

import { ServerLocation, Router } from "@reach/router";

31

32

// Basic server-side rendering

33

const renderApp = (url) => {

34

const appHtml = renderToString(

35

<ServerLocation url={url}>

36

<Router>

37

<Home path="/" />

38

<About path="/about" />

39

<Contact path="/contact" />

40

</Router>

41

</ServerLocation>

42

);

43

44

return `

45

<!DOCTYPE html>

46

<html>

47

<head><title>My App</title></head>

48

<body>

49

<div id="root">${appHtml}</div>

50

<script src="/client.js"></script>

51

</body>

52

</html>

53

`;

54

};

55

56

// Express.js integration

57

app.get("*", (req, res) => {

58

const html = renderApp(req.url);

59

res.send(html);

60

});

61

62

// Next.js style server rendering

63

const getServerSideProps = async (context) => {

64

const { req } = context;

65

const url = req.url;

66

67

return {

68

props: {

69

initialUrl: url

70

}

71

};

72

};

73

74

const Page = ({ initialUrl }) => (

75

<ServerLocation url={initialUrl}>

76

<App />

77

</ServerLocation>

78

);

79

80

// URL with query parameters and hash

81

const renderWithQuery = () => {

82

const url = "/search?q=react&category=library#results";

83

84

return renderToString(

85

<ServerLocation url={url}>

86

<Router>

87

<SearchResults path="/search" />

88

</Router>

89

</ServerLocation>

90

);

91

};

92

93

// Server rendering with dynamic routes

94

const renderUserPage = (userId) => {

95

const url = `/users/${userId}`;

96

97

return renderToString(

98

<ServerLocation url={url}>

99

<Router>

100

<UserProfile path="/users/:userId" />

101

</Router>

102

</ServerLocation>

103

);

104

};

105

```

106

107

### Server Location Context

108

109

Understanding the location context provided by ServerLocation for server-side rendering.

110

111

```javascript { .api }

112

/**

113

* ServerLocation provides a static location context

114

*/

115

interface ServerLocationContext {

116

location: {

117

pathname: string;

118

search: string;

119

hash: string;

120

};

121

navigate: () => never; // Throws error - navigation not allowed on server

122

}

123

```

124

125

**Usage Examples:**

126

127

```javascript

128

// Components receive parsed location on server

129

const SearchResults = ({ location }) => {

130

// On server: location = { pathname: "/search", search: "?q=react", hash: "" }

131

const query = new URLSearchParams(location.search).get("q");

132

133

return (

134

<div>

135

<h1>Search Results for: {query}</h1>

136

<p>Server-rendered at {location.pathname}</p>

137

</div>

138

);

139

};

140

141

// Server rendering with hooks

142

const HookComponent = () => {

143

const location = useLocation(); // Works on server with ServerLocation

144

145

return (

146

<div>

147

<p>Current path: {location.pathname}</p>

148

<p>Query string: {location.search}</p>

149

</div>

150

);

151

};

152

153

// Error handling for navigation attempts

154

const SafeNavigationComponent = () => {

155

const navigate = useNavigate();

156

157

const handleClick = () => {

158

if (typeof window !== "undefined") {

159

// Only navigate on client

160

navigate("/new-page");

161

} else {

162

console.log("Navigation attempted on server - ignored");

163

}

164

};

165

166

return <button onClick={handleClick}>Navigate</button>;

167

};

168

169

// Server-side route matching

170

const renderMatchedRoute = (url) => {

171

return renderToString(

172

<ServerLocation url={url}>

173

<Router>

174

<Home path="/" />

175

<User path="/users/:userId" />

176

<NotFound default />

177

</Router>

178

</ServerLocation>

179

);

180

};

181

```

182

183

### Server Rendering Patterns

184

185

Common patterns for implementing server-side rendering with Reach Router.

186

187

**Usage Examples:**

188

189

```javascript

190

// Isomorphic application structure

191

const App = ({ serverUrl }) => {

192

if (typeof window === "undefined") {

193

// Server-side rendering

194

return (

195

<ServerLocation url={serverUrl}>

196

<AppRoutes />

197

</ServerLocation>

198

);

199

} else {

200

// Client-side rendering

201

return (

202

<Router>

203

<AppRoutes />

204

</Router>

205

);

206

}

207

};

208

209

const AppRoutes = () => (

210

<>

211

<Home path="/" />

212

<About path="/about" />

213

<Contact path="/contact" />

214

</>

215

);

216

217

// Server-side data fetching

218

const renderWithData = async (url) => {

219

// Extract route parameters for data fetching

220

const match = matchPath("/users/:userId", url);

221

let userData = null;

222

223

if (match) {

224

userData = await fetchUser(match.params.userId);

225

}

226

227

return renderToString(

228

<ServerLocation url={url}>

229

<DataContext.Provider value={{ userData }}>

230

<Router>

231

<UserProfile path="/users/:userId" />

232

</Router>

233

</DataContext.Provider>

234

</ServerLocation>

235

);

236

};

237

238

// SEO optimization with server rendering

239

const renderSEOPage = (url, metadata) => {

240

const appHtml = renderToString(

241

<ServerLocation url={url}>

242

<Router>

243

<SEOPage path="/seo/*" metadata={metadata} />

244

</Router>

245

</ServerLocation>

246

);

247

248

return `

249

<!DOCTYPE html>

250

<html>

251

<head>

252

<title>${metadata.title}</title>

253

<meta name="description" content="${metadata.description}" />

254

<meta property="og:url" content="${metadata.canonicalUrl}" />

255

</head>

256

<body>

257

<div id="root">${appHtml}</div>

258

</body>

259

</html>

260

`;

261

};

262

263

// Hydration-friendly server rendering

264

const createSSRApp = (url) => {

265

const initialData = gatherInitialData(url);

266

267

const html = renderToString(

268

<ServerLocation url={url}>

269

<DataProvider initialData={initialData}>

270

<Router>

271

<AppRoutes />

272

</Router>

273

</DataProvider>

274

</ServerLocation>

275

);

276

277

return {

278

html,

279

initialData: JSON.stringify(initialData)

280

};

281

};

282

283

// Server-side rendering with error boundaries

284

const SafeServerApp = ({ url }) => (

285

<ServerLocation url={url}>

286

<ErrorBoundary>

287

<Router>

288

<Home path="/" />

289

<About path="/about" />

290

<ErrorPage default />

291

</Router>

292

</ErrorBoundary>

293

</ServerLocation>

294

);

295

296

class ErrorBoundary extends React.Component {

297

constructor(props) {

298

super(props);

299

this.state = { hasError: false };

300

}

301

302

static getDerivedStateFromError(error) {

303

return { hasError: true };

304

}

305

306

render() {

307

if (this.state.hasError) {

308

return <div>Something went wrong during server rendering.</div>;

309

}

310

311

return this.props.children;

312

}

313

}

314

```

315

316

### Client-Side Hydration

317

318

Handling the transition from server-rendered content to client-side routing.

319

320

**Usage Examples:**

321

322

```javascript

323

// Client-side hydration setup

324

import { hydrate } from "react-dom";

325

326

const ClientApp = () => (

327

<Router>

328

<AppRoutes />

329

</Router>

330

);

331

332

// Hydrate the server-rendered content

333

hydrate(<ClientApp />, document.getElementById("root"));

334

335

// Hydration with initial data

336

const hydrateWithData = (initialData) => {

337

const App = () => (

338

<DataProvider initialData={initialData}>

339

<Router>

340

<AppRoutes />

341

</Router>

342

</DataProvider>

343

);

344

345

hydrate(<App />, document.getElementById("root"));

346

};

347

348

// Read initial data from server

349

const initialDataScript = document.getElementById("initial-data");

350

const initialData = JSON.parse(initialDataScript.textContent);

351

hydrateWithData(initialData);

352

353

// Handling hydration mismatches

354

const HydrationSafeComponent = ({ children }) => {

355

const [hasMounted, setHasMounted] = React.useState(false);

356

357

React.useEffect(() => {

358

setHasMounted(true);

359

}, []);

360

361

if (!hasMounted) {

362

// Return server-safe content during hydration

363

return <div>{children}</div>;

364

}

365

366

// Return client-specific content after hydration

367

return <div className="client-hydrated">{children}</div>;

368

};

369

370

// Universal routing component

371

const UniversalApp = ({ initialUrl }) => {

372

const [isServer] = React.useState(typeof window === "undefined");

373

374

if (isServer) {

375

return (

376

<ServerLocation url={initialUrl}>

377

<AppRoutes />

378

</ServerLocation>

379

);

380

}

381

382

return (

383

<Router>

384

<AppRoutes />

385

</Router>

386

);

387

};

388

389

// Progressive enhancement approach

390

const ProgressiveApp = () => {

391

const [isHydrated, setIsHydrated] = React.useState(false);

392

393

React.useEffect(() => {

394

setIsHydrated(true);

395

}, []);

396

397

return (

398

<div>

399

{/* Always render core content */}

400

<header>My App</header>

401

402

{/* Conditionally render interactive features */}

403

{isHydrated ? (

404

<Router>

405

<InteractiveRoutes />

406

</Router>

407

) : (

408

<StaticContent />

409

)}

410

</div>

411

);

412

};

413

```