Skip to content

Commit a2431c0

Browse files
committed
improvements
1 parent 842c866 commit a2431c0

File tree

29 files changed

+78
-111
lines changed

29 files changed

+78
-111
lines changed

README.md

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ This workshop focuses on
99
data loading and display. It is designed to teach you the core concepts of
1010
react-router v7 in a hands-on, project-based way.
1111

12-
We will learn how to build an e-commerce app from scratch using react-router
13-
v7. Along the way, we will cover topics such as:
12+
We will learn how to build an e-commerce app from scratch using react-router v7.
13+
Along the way, we will cover topics such as:
14+
1415
- Setting up a react-router v7 project
1516
- Creating routes and nested routes
1617
- Loading data with loaders
@@ -20,17 +21,17 @@ v7. Along the way, we will cover topics such as:
2021
- Sorting, filtering, and paginating data
2122
- Progressive enhancement and accessibility
2223

23-
By the end of this workshop, you will have a solid understanding of how to
24-
use react-router v7 to build data-driven applications. You will also have a
25-
working e-commerce app that you can use as a starting point for your own
26-
projects.
24+
By the end of this workshop, you will have a solid understanding of how to use
25+
react-router v7 to build data-driven applications. You will also have a working
26+
e-commerce app that you can use as a starting point for your own projects.
27+
28+
This workshop assumes you have a basic understanding of React and JavaScript. No
29+
prior knowledge of react-router is required.
2730

28-
This workshop assumes you have a basic understanding of React and
29-
JavaScript. No prior knowledge of react-router is required.
3031
</p>
3132
</div>
3233

33-
34+
3435

3536
<hr />
3637

@@ -73,12 +74,18 @@ speed on some of the tools and concepts we'll be covering:
7374
- https://react.dev/blog/2024/12/05/react-19 (React 19 blog post)
7475
- https://react.dev/learn (React official docs - learn section)
7576
- https://reactrouter.com/home (React Router official docs)
76-
- https://www.typescriptlang.org/docs/handbook/2/basic-types.html (TypeScript basic types docs)
77+
- https://www.typescriptlang.org/docs/handbook/2/basic-types.html (TypeScript
78+
basic types docs)
7779

7880
Useful to go through if you want to get a head start on the workshop:
79-
- https://v2.remix.run/docs/discussion/introduction (Remix introduction docs, keep in mind that react-router v7 framework mode is a continuation of Remix v2)
80-
- https://v2.remix.run/docs/discussion/progressive-enhancement (Progressive enhancement in Remix, also applicable to react-router v7 framework mode)
81-
- https://developer.mozilla.org/en-US/ (this is your best friend for web development, check out anything you don't understand here)
81+
82+
- https://v2.remix.run/docs/discussion/introduction (Remix introduction docs,
83+
keep in mind that react-router v7 framework mode is a continuation of Remix
84+
v2)
85+
- https://v2.remix.run/docs/discussion/progressive-enhancement (Progressive
86+
enhancement in Remix, also applicable to react-router v7 framework mode)
87+
- https://developer.mozilla.org/en-US/ (this is your best friend for web
88+
development, check out anything you don't understand here)
8289

8390
## System Requirements
8491

epicshop/setup-custom.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@ if (!process.env.SKIP_PRISMA) {
5454
const prismaDir = path.join(app.fullPath, 'prisma')
5555
try {
5656
if (await fsExtra.exists(prismaDir)) {
57-
await execa(`npm`, ["run", "db:gen"], { cwd: app.fullPath, all: true })
57+
await execa(`npm`, ['run', 'db:gen'], { cwd: app.fullPath, all: true })
5858
}
5959
} catch (prismaGenerateResult) {
6060
console.log(prismaGenerateResult.all)
6161
throw new Error(`❌ prisma generate failed in ${app.relativePath}`)
6262
}
6363
}
6464
console.log('✅ prisma client generated')
65-
}
65+
}

exercises/01.routing/02.problem.automatic-routing/README.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Now that we understand how to define routes and use them effectively, let's use
88
from the React Router team to automatically detect and register routes for us so we can focus
99
on building features instead of boilerplate.
1010

11+
📜 https://reactrouter.com/how-to/file-route-conventions
12+
1113
## Exercise Goals
1214

1315
In this exercise, you will:

exercises/02.metadata/01.problem.styling/app/root.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const links: Route.LinksFunction = () => [
1414
// 🐨 Add the stylesheet imported from app.css!
1515
// 🐨 Add fonts and preconnect to google!
1616
// 💰 Use this to preconnect to google fonts
17+
// 📜 https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preconnect
1718
// { rel: 'preconnect', href: 'https://fonts.googleapis.com' },
1819
// 💰 Use this to preconnect to google fonts
1920
// { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossOrigin: 'anonymous' },

exercises/02.metadata/01.solution.styling/app/root.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import tailwindStylesheet from './app.css?url'
1111
import { EpicShop } from './epicshop'
1212

1313
export const links: Route.LinksFunction = () => [
14-
// 📜 https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preconnect
1514
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
1615
{ rel: 'stylesheet', href: tailwindStylesheet },
1716
{

exercises/02.metadata/03.problem.titles-with-meta/app/routes/_landing._index/route.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { FeaturesSection } from './features-section'
1111
import { HeroSection } from './hero-section'
1212
import { NewsletterSection } from './newsletter-section'
1313

14-
// 🐨 We want to include the root meta in the title to have Epic Shop | Terms of Use
14+
// 🐨 We want to include the root meta in the title to have Epic Shop
1515
export const meta: Route.MetaFunction = ({ matches }) => {
1616
// 💰 You can use getMetaFromMatches and specify "root" to extract the meta information from root
1717
// 💰 You can use getMetaTitle to extract the title from the root meta information

exercises/02.metadata/03.problem.titles-with-meta/app/routes/_landing.products.$productId.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
Plus,
99
Minus,
1010
} from 'lucide-react'
11-
import React, { useState } from 'react'
11+
import { useState } from 'react'
1212
import { useParams, Link } from 'react-router'
1313
import {
1414
getMetaFromMatches,
@@ -19,8 +19,8 @@ import { products } from '../../data/products'
1919
// 💰 You will need these utilities! Feel free to check their implementation first!
2020
import { type Route } from './+types/_landing.products.$productId'
2121

22-
// 🐨 We want to include the root meta in the title to have Epic Shop | Product overview
23-
export const meta: Route.MetaFunction = ({ matches }) => {
22+
// 🐨 We want to include the root meta in the title to have Epic Shop | Product overview ${productId}
23+
export const meta: Route.MetaFunction = ({ matches, params }) => {
2424
// 💰 You can use getMetaFromMatches and specify "root" to extract the meta information from root
2525
// 💰 You can use getMetaTitle to extract the title from the root meta information
2626
return [

exercises/02.metadata/03.problem.titles-with-meta/tests/e2e/metadata.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ test.describe('Routing E2E Tests', () => {
88
await expect(page).toHaveTitle('Epic Shop')
99

1010
// Check for duplicate <title> elements
11-
const titleElements = page.locator('title')
11+
const titleElements = page.locator('head > title')
1212
await expect(titleElements).toHaveCount(1)
1313
})
1414

@@ -18,7 +18,7 @@ test.describe('Routing E2E Tests', () => {
1818
await page.goto('/products')
1919
await expect(page).toHaveTitle('Epic Shop | All Products')
2020
// Check for duplicate <title> elements
21-
const titleElements = page.locator('title')
21+
const titleElements = page.locator('head > title')
2222
await expect(titleElements).toHaveCount(1)
2323
})
2424

@@ -28,7 +28,7 @@ test.describe('Routing E2E Tests', () => {
2828
await page.goto('/products/1')
2929
await expect(page).toHaveTitle('Epic Shop | Product overview')
3030
// Check for duplicate <title> elements
31-
const titleElements = page.locator('title')
31+
const titleElements = page.locator('head > title')
3232
await expect(titleElements).toHaveCount(1)
3333
})
3434
})

exercises/02.metadata/03.solution.titles-with-meta/app/routes/_landing.products.$productId.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@ import {
1818
import { products } from '../../data/products'
1919
import { type Route } from './+types/_landing.products.$productId'
2020

21-
export const meta: Route.MetaFunction = ({ matches }) => {
21+
export const meta: Route.MetaFunction = ({ matches, params }) => {
2222
const rootMeta = getMetaFromMatches(matches, 'root')
2323
const prefix = getMetaTitle(rootMeta)
2424
return [
2525
{
26-
title: constructPrefixedTitle('Product overview', prefix),
26+
title: constructPrefixedTitle(
27+
`Product overview ${params.productId}`,
28+
prefix,
29+
),
2730
},
2831
]
2932
}

exercises/03.data-fetching/01.problem.fetching-with-loaders/README.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ a different concept of data fetching with loaders:
4747

4848
1. **Basic Data Fetching**: In the first route, we will implement a simple loader that fetches
4949
all products from the database and displays them on the page. This will help you understand
50-
the basics of setting up a loader and using the fetched data in your components. (`_landing._index.route.tsx`)
50+
the basics of setting up a loader and using the fetched data in your components. (`_landing._index/route.tsx`)
5151
2. **Using URL Parameters**: The second route will introduce URL parameters. We will create a loader
5252
that fetches a product based on the ID provided in the URL. This will teach you how to read
53-
URL parameters in loaders and use them to fetch specific data. (`_landing.products.$productId.route.tsx`)
53+
URL parameters in loaders and use them to fetch specific data. (`_landing.products.$productId.tsx`)
5454
3. **Optimizing Data Fetching**: In the final route, we will focus on optimizing our data fetching.
5555
We will use a simple trick of parallelizing multiple data fetches to improve performance. This will help you
5656
understand how to make your loaders more efficient. (`_landing.products._index/route.tsx`)

0 commit comments

Comments
 (0)