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

advanced-routing.mddocs/

0

# Advanced Routing

1

2

Advanced routing patterns including redirects, conditional rendering, and route matching utilities.

3

4

## Capabilities

5

6

### Redirect Component

7

8

Declarative redirect component for programmatic navigation during rendering.

9

10

```javascript { .api }

11

/**

12

* Declarative redirect component for programmatic navigation

13

* @param props - Redirect configuration

14

*/

15

function Redirect(props: {

16

from?: string;

17

to: string;

18

replace?: boolean;

19

state?: any;

20

noThrow?: boolean;

21

}): React.ReactElement;

22

```

23

24

**Props:**

25

- `from` (string, optional) - Source path pattern (only used inside Router)

26

- `to` (string, required) - Destination path

27

- `replace` (boolean, optional) - Replace current history entry (defaults to true)

28

- `state` (any, optional) - State to pass with redirect

29

- `noThrow` (boolean, optional) - Don't throw redirect error (for server rendering)

30

31

**Usage Examples:**

32

33

```javascript

34

import React from "react";

35

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

36

37

// Basic redirect

38

const App = () => (

39

<Router>

40

<Home path="/" />

41

<Redirect from="/home" to="/" />

42

<About path="/about" />

43

</Router>

44

);

45

46

// Redirect with parameters

47

const App = () => (

48

<Router>

49

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

50

<Redirect from="/profile/:userId" to="/users/:userId" />

51

</Router>

52

);

53

54

// Conditional redirect based on authentication

55

const ProtectedRoute = ({ component: Component, ...props }) => {

56

const isAuthenticated = useAuth();

57

58

if (!isAuthenticated) {

59

return <Redirect to="/login" state={{ from: props.path }} />;

60

}

61

62

return <Component {...props} />;

63

};

64

65

<Router>

66

<Login path="/login" />

67

<ProtectedRoute component={Dashboard} path="/dashboard" />

68

</Router>

69

70

// Redirect with state

71

const LoginRedirect = () => (

72

<Redirect

73

to="/dashboard"

74

state={{ message: "Successfully logged in!" }}

75

/>

76

);

77

78

// Server-safe redirect

79

const ServerSafeRedirect = ({ to }) => (

80

<Redirect to={to} noThrow />

81

);

82

83

// Multiple redirects for old URLs

84

const LegacyRedirects = () => (

85

<Router>

86

<Home path="/" />

87

<Redirect from="/old-home" to="/" />

88

<Redirect from="/legacy/about" to="/about" />

89

<Redirect from="/v1/users/:id" to="/users/:id" />

90

<About path="/about" />

91

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

92

</Router>

93

);

94

```

95

96

### Match Component

97

98

Render prop component for conditional rendering based on path matching without routing.

99

100

```javascript { .api }

101

/**

102

* Render prop component for conditional rendering based on path matching

103

* @param props - Match configuration

104

*/

105

function Match(props: {

106

path: string;

107

children: (props: MatchRenderProps) => React.ReactNode;

108

}): React.ReactElement;

109

110

interface MatchRenderProps {

111

navigate: (to: string | number, options?: NavigateOptions) => Promise<void>;

112

location: Location;

113

match: MatchResult | null;

114

}

115

116

interface MatchResult {

117

uri: string; // Always normalized with leading slash

118

path: string;

119

[paramName: string]: string | string[]; // Can contain arrays for splat routes

120

}

121

```

122

123

**Usage Examples:**

124

125

```javascript

126

import React from "react";

127

import { Match } from "@reach/router";

128

129

// Conditional navigation based on match

130

const ConditionalNav = () => (

131

<Match path="/admin/*">

132

{({ match }) => (

133

<nav>

134

<Link to="/">Home</Link>

135

{match && (

136

<>

137

<Link to="/admin/users">Users</Link>

138

<Link to="/admin/settings">Settings</Link>

139

</>

140

)}

141

</nav>

142

)}

143

</Match>

144

);

145

146

// Dynamic styling based on path match

147

const Header = () => (

148

<Match path="/products/*">

149

{({ match, location }) => (

150

<header className={match ? "products-header" : "default-header"}>

151

<h1>My Store</h1>

152

{match && <p>Browsing: {location.pathname}</p>}

153

</header>

154

)}

155

</Match>

156

);

157

158

// Multiple matches for complex layouts

159

const Layout = ({ children }) => (

160

<div>

161

<Match path="/dashboard/*">

162

{({ match }) => match && <DashboardSidebar />}

163

</Match>

164

165

<Match path="/admin/*">

166

{({ match }) => match && <AdminToolbar />}

167

</Match>

168

169

<main>{children}</main>

170

</div>

171

);

172

173

// Match with parameter extraction

174

const BreadcrumbTrail = () => (

175

<Match path="/users/:userId/posts/:postId">

176

{({ match, navigate }) => {

177

if (!match) return null;

178

179

const { userId, postId } = match;

180

181

return (

182

<nav className="breadcrumb">

183

<button onClick={() => navigate("/")}>Home</button>

184

<span> / </span>

185

<button onClick={() => navigate("/users")}>Users</button>

186

<span> / </span>

187

<button onClick={() => navigate(`/users/${userId}`)}>

188

User {userId}

189

</button>

190

<span> / </span>

191

<span>Post {postId}</span>

192

</nav>

193

);

194

}}

195

</Match>

196

);

197

198

// Conditional component mounting

199

const FeatureToggle = ({ feature, children }) => (

200

<Match path={`/features/${feature}/*`}>

201

{({ match }) => match ? children : null}

202

</Match>

203

);

204

205

<FeatureToggle feature="beta">

206

<BetaFeatures />

207

</FeatureToggle>

208

```

209

210

### matchPath Utility

211

212

Programmatic route matching utility for checking if a path matches a pattern outside of components.

213

214

```javascript { .api }

215

/**

216

* Programmatic route matching utility

217

* @param path - Path pattern to match against

218

* @param uri - URI to test for matching

219

* @returns Match result with params and uri, or null if no match

220

*/

221

function matchPath(path: string, uri: string): MatchResult | null;

222

223

interface MatchResult {

224

route: {

225

path: string;

226

};

227

params: Record<string, string | string[]>; // Can contain arrays for splat routes

228

uri: string; // Always normalized with leading slash

229

}

230

```

231

232

**Usage Examples:**

233

234

```javascript

235

import { matchPath } from "@reach/router";

236

237

// Basic path matching

238

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

239

if (match) {

240

console.log(match.params.userId); // "123"

241

console.log(match.uri); // "/users/123"

242

}

243

244

// Wildcard matching

245

const wildcardMatch = matchPath("/files/*", "/files/docs/readme.txt");

246

if (wildcardMatch) {

247

console.log(wildcardMatch.params["*"]); // "docs/readme.txt"

248

}

249

250

// Route-based data fetching

251

const fetchRouteData = async (pathname) => {

252

const userMatch = matchPath("/users/:userId", pathname);

253

if (userMatch) {

254

return await fetchUser(userMatch.params.userId);

255

}

256

257

const postMatch = matchPath("/posts/:postId", pathname);

258

if (postMatch) {

259

return await fetchPost(postMatch.params.postId);

260

}

261

262

return null;

263

};

264

265

// Server-side route matching

266

const getServerSideProps = async (context) => {

267

const { req } = context;

268

const pathname = req.url;

269

270

const match = matchPath("/products/:productId", pathname);

271

if (match) {

272

const product = await fetchProduct(match.params.productId);

273

return { props: { product } };

274

}

275

276

return { props: {} };

277

};

278

279

// Route guards and middleware

280

const routeGuards = [

281

{

282

pattern: "/admin/*",

283

guard: (match, user) => user?.isAdmin

284

},

285

{

286

pattern: "/users/:userId/*",

287

guard: (match, user) => user?.id === match.params.userId

288

}

289

];

290

291

const checkAccess = (pathname, user) => {

292

for (const { pattern, guard } of routeGuards) {

293

const match = matchPath(pattern, pathname);

294

if (match && !guard(match, user)) {

295

return false;

296

}

297

}

298

return true;

299

};

300

301

// Dynamic route configuration

302

const routes = [

303

{ pattern: "/", component: "Home" },

304

{ pattern: "/about", component: "About" },

305

{ pattern: "/users/:userId", component: "UserProfile" },

306

{ pattern: "/posts/:postId", component: "PostDetail" }

307

];

308

309

const findMatchingRoute = (pathname) => {

310

for (const route of routes) {

311

const match = matchPath(route.pattern, pathname);

312

if (match) {

313

return { ...route, match };

314

}

315

}

316

return null;

317

};

318

```

319

320

### Redirect Utilities

321

322

Utility functions for handling redirects programmatically.

323

324

```javascript { .api }

325

/**

326

* Check if an error is a redirect request

327

* @param error - Error object to check

328

* @returns True if error is a redirect request

329

*/

330

function isRedirect(error: any): boolean;

331

332

/**

333

* Throw a redirect request for error boundary handling

334

* @param to - Destination path

335

* @throws RedirectRequest that can be caught by error boundaries

336

*/

337

function redirectTo(to: string): never;

338

```

339

340

**Usage Examples:**

341

342

```javascript

343

import { isRedirect, redirectTo } from "@reach/router";

344

345

// Error boundary handling redirects

346

class RedirectBoundary extends React.Component {

347

componentDidCatch(error, errorInfo) {

348

if (isRedirect(error)) {

349

// Handle redirect in error boundary

350

console.log("Caught redirect to:", error.uri);

351

// The redirect will be handled automatically

352

} else {

353

// Handle other errors

354

console.error("Component error:", error);

355

}

356

}

357

358

render() {

359

return this.props.children;

360

}

361

}

362

363

// Programmatic redirects in components

364

const AuthCheck = ({ children }) => {

365

const user = useAuth();

366

367

React.useEffect(() => {

368

if (!user) {

369

// Throw redirect that will be caught by LocationProvider

370

redirectTo("/login");

371

}

372

}, [user]);

373

374

return user ? children : null;

375

};

376

377

// Conditional redirects in render

378

const ConditionalRedirect = ({ condition, to, children }) => {

379

if (condition) {

380

redirectTo(to);

381

}

382

383

return children;

384

};

385

386

// Redirect with data validation

387

const ValidatedRoute = ({ data, fallback, children }) => {

388

React.useEffect(() => {

389

if (!data || !data.isValid) {

390

redirectTo(fallback);

391

}

392

}, [data, fallback]);

393

394

return data?.isValid ? children : null;

395

};

396

397

// Error handling with redirect detection

398

const handleAsyncAction = async () => {

399

try {

400

await performAction();

401

} catch (error) {

402

if (isRedirect(error)) {

403

// Don't log redirect errors

404

return;

405

}

406

407

// Log and handle other errors

408

console.error("Action failed:", error);

409

redirectTo("/error");

410

}

411

};

412

413

// Custom redirect hook

414

const useRedirectIf = (condition, to) => {

415

React.useEffect(() => {

416

if (condition) {

417

redirectTo(to);

418

}

419

}, [condition, to]);

420

};

421

422

// Usage of custom hook

423

const ProtectedComponent = () => {

424

const user = useAuth();

425

useRedirectIf(!user, "/login");

426

427

return <div>Protected content</div>;

428

};

429

```

430

431

### Advanced Route Patterns

432

433

Complex routing patterns and techniques for sophisticated applications.

434

435

**Usage Examples:**

436

437

```javascript

438

// Route-based code splitting

439

const LazyRoute = ({ component, ...props }) => {

440

const [Component, setComponent] = React.useState(null);

441

442

React.useEffect(() => {

443

import(`../components/${component}`)

444

.then(module => setComponent(() => module.default));

445

}, [component]);

446

447

if (!Component) {

448

return <div>Loading...</div>;

449

}

450

451

return <Component {...props} />;

452

};

453

454

<Router>

455

<LazyRoute component="Home" path="/" />

456

<LazyRoute component="About" path="/about" />

457

</Router>

458

459

// Nested routing with context

460

const NestedRoutes = () => (

461

<Router>

462

<Dashboard path="/dashboard/*">

463

<DashboardHome path="/" />

464

<Settings path="/settings/*">

465

<GeneralSettings path="/" />

466

<SecuritySettings path="/security" />

467

<ProfileSettings path="/profile" />

468

</Settings>

469

</Dashboard>

470

</Router>

471

);

472

473

// Route-based theming

474

const ThemedRouter = () => {

475

const location = useLocation();

476

const theme = getThemeForPath(location.pathname);

477

478

return (

479

<ThemeProvider theme={theme}>

480

<Router>

481

<Home path="/" />

482

<Admin path="/admin/*" />

483

<Public path="/public/*" />

484

</Router>

485

</ThemeProvider>

486

);

487

};

488

489

// Dynamic route generation

490

const DynamicRoutes = ({ routes }) => (

491

<Router>

492

{routes.map(route => {

493

const Component = route.component;

494

return (

495

<Component

496

key={route.path}

497

path={route.path}

498

{...route.props}

499

/>

500

);

501

})}

502

</Router>

503

);

504

505

// Route transition animations

506

const AnimatedRouter = ({ children }) => {

507

const location = useLocation();

508

509

return (

510

<TransitionGroup>

511

<CSSTransition

512

key={location.pathname}

513

classNames="route"

514

timeout={300}

515

>

516

<Router location={location}>

517

{children}

518

</Router>

519

</CSSTransition>

520

</TransitionGroup>

521

);

522

};

523

```