Kurs JavaScript i React · Moduł 1: Podstawy React
Struktura projektu React
W tej lekcji8
Dobrze zorganizowana struktura projektu jest kluczowa dla utrzymania kodu, łatwej nawigacji i skalowalności aplikacji React. W tej lekcji przyjrzymy się najlepszym praktykom strukturyzowania projektów React i zrozumiemy, jak organizować pliki i komponenty.
Podstawowa struktura projektu React
Niezależnie od narzędzia, rozbudowany projekt React (tu na przykładzie Vite) ma zwykle podobną strukturę:
1moj-projekt-react/
2├── node_modules/ # Zainstalowane zależności
3├── public/ # Pliki statyczne dostępne publicznie
4├── src/ # Kod źródłowy aplikacji
5│ ├── components/ # Komponenty wielokrotnego użytku
6│ ├── pages/ # Komponenty reprezentujące całe strony
7│ ├── assets/ # Zasoby takie jak obrazy, fonty itp.
8│ ├── utils/ # Funkcje pomocnicze
9│ ├── services/ # Kod odpowiedzialny za komunikację API
10│ ├── hooks/ # Niestandardowe hooki React
11│ ├── context/ # Konteksty React
12│ ├── App.jsx # Główny komponent aplikacji
13│ └── main.jsx # Punkt wejściowy aplikacji
14├── index.html # Strona HTML, do której trafia aplikacja
15├── vite.config.js # Konfiguracja Vite
16├── .gitignore # Pliki ignorowane przez Git
17├── package.json # Informacje o projekcie i zależności
18└── README.md # Dokumentacja projektuOmówmy najważniejsze katalogi i ich przeznaczenie:
Katalog src/
Katalog src/ to serce Twojej aplikacji React. Zawiera całą logikę, komponenty i zasoby. Oto jak zazwyczaj organizuje się ten katalog:
components/
Zawiera komponenty wielokrotnego użytku, które są używane w różnych częściach aplikacji. Istnieje kilka podejść do strukturyzowania komponentów:
Struktura płaska
1components/
2├── Button.jsx
3├── Button.css
4├── Header.jsx
5├── Header.css
6├── Footer.jsx
7└── Footer.cssStruktura pogrupowana (preferowana dla większych projektów)
1components/
2├── Button/
3│ ├── Button.jsx
4│ ├── Button.css
5│ └── index.js
6├── Header/
7│ ├── Header.jsx
8│ ├── Header.css
9│ └── index.js
10└── Footer/
11 ├── Footer.jsx
12 ├── Footer.css
13 └── index.jsUżywanie plików index.js do eksportowania komponentów upraszcza importy:
1// Zamiast:
2import Button from './components/Button/Button';
3
4// Możesz pisać:
5import Button from './components/Button';pages/
Komponenty reprezentujące całe strony lub widoki w aplikacji. W projektach z routingiem, każdy plik w tym katalogu zazwyczaj odpowiada określonej ścieżce URL:
1pages/
2├── Home/
3│ ├── Home.jsx
4│ └── Home.css
5├── About/
6│ ├── About.jsx
7│ └── About.css
8└── Dashboard/
9 ├── Dashboard.jsx
10 └── Dashboard.cssassets/
Zawiera wszystkie statyczne zasoby używane w aplikacji:
1assets/
2├── images/
3│ ├── logo.png
4│ └── background.jpg
5├── fonts/
6│ ├── roboto.ttf
7│ └── open-sans.ttf
8└── styles/
9 ├── variables.css
10 └── global.cssutils/
Funkcje pomocnicze i narzędzia używane w całej aplikacji:
1utils/
2├── formatDate.js
3├── validation.js
4└── helpers.jsservices/
Kod odpowiedzialny za komunikację z zewnętrznymi API lub usługami:
1services/
2├── api.js # Podstawowa konfiguracja API
3├── userService.js # Zapytania związane z użytkownikami
4└── productService.js # Zapytania związane z produktamihooks/
Niestandardowe hooki React, które można używać w wielu miejscach aplikacji:
1hooks/
2├── useLocalStorage.js
3├── useFetch.js
4└── useForm.jscontext/
Konteksty React używane do zarządzania globalnym stanem:
1context/
2├── AuthContext.js
3├── ThemeContext.js
4└── CartContext.jsOrganizacja według funkcji vs. według typu
Istnieją dwa główne podejścia do organizacji kodu:
Organizacja według typu (pokazana powyżej)
Pliki są grupowane według ich typu (komponenty, hooki, usługi itp.).
Organizacja według funkcji
Pliki są grupowane według funkcji lub części aplikacji:
1src/
2├── auth/
3│ ├── components/
4│ ├── hooks/
5│ ├── services/
6│ └── context/
7├── products/
8│ ├── components/
9│ ├── hooks/
10│ ├── services/
11│ └── utils/
12└── checkout/
13 ├── components/
14 ├── hooks/
15 └── services/Ta struktura jest bardziej skalowalna dla dużych projektów, szczególnie gdy pracuje nad nimi wiele osób.
Konwencje nazewnictwa
Spójne nazewnictwo jest równie ważne jak struktura katalogów:
Komponenty
- Używaj PascalCase:
Button.jsx,UserProfile.jsx - Pliki JSX powinny mieć rozszerzenie
.jsx(nie jest to konieczne, ale pomaga w identyfikacji)
Hooki
- Zawsze zaczynaj od "use":
useLocalStorage.js,useWindowSize.js
Konteksty
- Zazwyczaj kończą się na "Context":
AuthContext.js,ThemeContext.js
Usługi i narzędzia
- Używaj camelCase:
apiService.js,formatDate.js
Style w React
Istnieje kilka podejść do organizacji stylów w React:
CSS Modules
1Button/
2├── Button.jsx
3└── Button.module.cssStyled Components
1Button/
2└── Button.jsx # Zawiera definicje styled-componentsSCSS/SASS
1Button/
2├── Button.jsx
3└── Button.scssDobre praktyki struktury folderów
W kosmicznej flocie React, dobrze zorganizowana struktura folderów to jak efektywny system logistyczny na statku kosmicznym - wszystko ma swoje miejsce i można szybko znaleźć to, czego potrzebujemy. Oto sprawdzone praktyki organizacji projektów React.
Organizacja według funkcji a według typu
Dwa główne podejścia do organizacji kodu w projektach React:
Organizacja według typu (type-based)
Pliki grupowane według ich roli technicznej - wszystkie komponenty razem, wszystkie hooki razem, etc.
1src/
2├── components/
3│ ├── Button/
4│ ├── Card/
5│ ├── Modal/
6│ ├── UserProfile/
7│ ├── ProductCard/
8│ └── ShoppingCart/
9├── hooks/
10│ ├── useAuth.js
11│ ├── useProducts.js
12│ └── useCart.js
13├── services/
14│ ├── authService.js
15│ ├── productService.js
16│ └── cartService.js
17└── utils/
18 ├── validators.js
19 └── formatters.jsZalety:
- Prostsza dla małych i średnich projektów
- Łatwa do zrozumienia dla nowych programistów
- Dobra dla aplikacji SPA bez wyraźnych modułów
Wady:
- W dużych projektach trudno znaleźć wszystkie pliki związane z jedną funkcjonalnością
- Komponenty z różnych funkcjonalności są wymieszane
- Trudniejsze do skalowania w zespołach
Organizacja według funkcji (feature-based)
Pliki grupowane według funkcjonalności biznesowej - wszystkie pliki dotyczące autentykacji razem, wszystkie dotyczące produktów razem, etc.
1src/
2├── features/
3│ ├── auth/
4│ │ ├── components/
5│ │ │ ├── LoginForm/
6│ │ │ ├── RegisterForm/
7│ │ │ └── PasswordReset/
8│ │ ├── hooks/
9│ │ │ ├── useAuth.js
10│ │ │ └── useSession.js
11│ │ ├── services/
12│ │ │ └── authService.js
13│ │ ├── utils/
14│ │ │ └── validators.js
15│ │ └── index.js
16│ │
17│ ├── products/
18│ │ ├── components/
19│ │ │ ├── ProductList/
20│ │ │ ├── ProductCard/
21│ │ │ └── ProductDetails/
22│ │ ├── hooks/
23│ │ │ ├── useProducts.js
24│ │ │ └── useProductFilters.js
25│ │ ├── services/
26│ │ │ └── productService.js
27│ │ └── index.js
28│ │
29│ └── cart/
30│ ├── components/
31│ │ ├── ShoppingCart/
32│ │ ├── CartItem/
33│ │ └── Checkout/
34│ ├── hooks/
35│ │ └── useCart.js
36│ ├── services/
37│ │ └── cartService.js
38│ └── index.js
39│
40├── shared/
41│ ├── components/
42│ │ ├── Button/
43│ │ ├── Modal/
44│ │ └── Card/
45│ ├── hooks/
46│ │ ├── useLocalStorage.js
47│ │ └── useDebounce.js
48│ └── utils/
49│ ├── formatDate.js
50│ └── formatCurrency.js
51│
52└── App.jsxZalety:
- Łatwiejsze skalowanie dla dużych projektów
- Wszystkie pliki związane z funkcją są w jednym miejscu
- Łatwiejsze do pracy w zespołach (różne zespoły mogą pracować nad różnymi funkcjami)
- Łatwiejsze do usuwania całych funkcjonalności
- Lepsze dla code splitting
Wady:
- Bardziej skomplikowana dla początkujących
- Wymaga więcej przemyślenia przy projektowaniu
- Może prowadzić do duplikacji dla bardzo małych komponentów
Konwencje nazewnictwa
Spójne nazewnictwo to kluczowy element dobrze zorganizowanego projektu. W React obowiązują następujące konwencje:
Komponenty - PascalCase
1// DOBRZE - PascalCase
2Button.jsx
3UserProfile.jsx
4ShoppingCart.jsx
5ProductCard.jsx
6
7// ŹLE - inne konwencje
8button.jsx
9user-profile.jsx
10shopping_cart.jsxDlaczego PascalCase?
- Odróżnia komponenty React od zwykłych funkcji
- Konwencja przyjęta w całym ekosystemie React
- JSX wymaga PascalCase dla komponentów (niestandardowe tagi)
Hooki - camelCase z przedrostkiem "use"
1// DOBRZE - camelCase z "use"
2useAuth.js
3useLocalStorage.js
4useWindowSize.js
5useProductFilters.js
6
7// ŹLE - brak "use" lub zła konwencja
8Auth.js
9local-storage.js
10WindowSize.jsDlaczego "use" prefix?
- React wymaga aby niestandardowe hooki zaczynały się od "use"
- Pozwala React na walidację reguł hooków
- Natychmiast komunikuje, że to hook
Konteksty - PascalCase z sufiksem "Context"
1// DOBRZE - PascalCase z "Context"
2AuthContext.js
3ThemeContext.js
4CartContext.js
5UserPreferencesContext.js
6
7// ŹLE - brak "Context" lub zła konwencja
8auth.js
9theme-context.js
10Cart.jsUtils i services - camelCase
1// DOBRZE - camelCase
2formatDate.js
3validateEmail.js
4apiService.js
5authService.js
6
7// ŹLE - inne konwencje
8FormatDate.js
9validate-email.js
10API_Service.jsGdzie trzymać różne typy plików
Rozplanowanie lokalizacji plików w projekcie ma ogromne znaczenie dla jego czytelności i skalowalności.
Hooks (niestandardowe hooki)
Feature-based approach:
1features/
2├── auth/
3│ └── hooks/
4│ ├── useAuth.js
5│ └── useSession.js
6└── products/
7 └── hooks/
8 └── useProducts.js
9
10shared/
11└── hooks/
12 ├── useLocalStorage.js # Współdzielony hook
13 ├── useDebounce.js # Współdzielony hook
14 └── useFetch.js # Współdzielony hookType-based approach:
1hooks/
2├── useAuth.js
3├── useSession.js
4├── useProducts.js
5├── useLocalStorage.js
6├── useDebounce.js
7└── useFetch.jsUtils (funkcje pomocnicze)
Feature-based approach:
1features/
2├── products/
3│ └── utils/
4│ ├── formatPrice.js
5│ └── filterProducts.js
6└── auth/
7 └── utils/
8 └── validatePassword.js
9
10shared/
11└── utils/
12 ├── formatDate.js # Współdzielone
13 ├── debounce.js # Współdzielone
14 └── cloneDeep.js # WspółdzieloneType-based approach:
1utils/
2├── formatPrice.js
3├── formatDate.js
4├── validatePassword.js
5├── filterProducts.js
6├── debounce.js
7└── cloneDeep.jsTypes (TypeScript)
Jeśli używasz TypeScript, masz kilka opcji dla typów:
Opcja 1: Obok plików, które używają:
1components/
2└── Button/
3 ├── Button.tsx
4 ├── Button.types.ts # Typy tylko dla Button
5 ├── Button.styles.ts
6 └── index.tsOpcja 2: Scentralizowane typy:
1types/
2├── user.types.ts
3├── product.types.ts
4├── cart.types.ts
5└── api.types.tsOpcja 3: Hybrydowe (najlepsze):
1features/
2└── products/
3 ├── components/
4 ├── types/ # Typy specyficzne dla feature
5 │ ├── product.types.ts
6 │ └── filter.types.ts
7 └── index.ts
8
9shared/
10└── types/ # Typy współdzielone
11 ├── common.types.ts
12 └── api.types.tsPrzykładowa struktura projektu - najlepsze praktyki
Połączenie feature-based dla głównych funkcjonalności i type-based dla współdzielonych zasobów:
1moja-aplikacja-react/
2├── public/
3├── src/
4│ ├── features/ # Główne funkcjonalności
5│ │ ├── auth/
6│ │ │ ├── components/
7│ │ │ │ ├── LoginForm/
8│ │ │ │ │ ├── LoginForm.tsx
9│ │ │ │ │ ├── LoginForm.styles.ts
10│ │ │ │ │ ├── LoginForm.test.tsx
11│ │ │ │ │ └── index.ts
12│ │ │ │ └── RegisterForm/
13│ │ │ ├── hooks/
14│ │ │ │ ├── useAuth.ts
15│ │ │ │ └── useSession.ts
16│ │ │ ├── services/
17│ │ │ │ └── authService.ts
18│ │ │ ├── types/
19│ │ │ │ └── auth.types.ts
20│ │ │ └── index.ts
21│ │ │
22│ │ ├── products/
23│ │ │ ├── components/
24│ │ │ │ ├── ProductList/
25│ │ │ │ ├── ProductCard/
26│ │ │ │ └── ProductFilters/
27│ │ │ ├── hooks/
28│ │ │ │ ├── useProducts.ts
29│ │ │ │ └── useProductFilters.ts
30│ │ │ ├── services/
31│ │ │ │ └── productService.ts
32│ │ │ ├── types/
33│ │ │ │ └── product.types.ts
34│ │ │ └── index.ts
35│ │ │
36│ │ └── cart/
37│ │ └── [podobna struktura]
38│ │
39│ ├── shared/ # Współdzielone zasoby
40│ │ ├── components/
41│ │ │ ├── Button/
42│ │ │ │ ├── Button.tsx
43│ │ │ │ ├── Button.styles.ts
44│ │ │ │ ├── Button.test.tsx
45│ │ │ │ └── index.ts
46│ │ │ ├── Modal/
47│ │ │ ├── Card/
48│ │ │ └── Layout/
49│ │ │
50│ │ ├── hooks/
51│ │ │ ├── useLocalStorage.ts
52│ │ │ ├── useDebounce.ts
53│ │ │ └── useFetch.ts
54│ │ │
55│ │ ├── utils/
56│ │ │ ├── formatDate.ts
57│ │ │ ├── validators.ts
58│ │ │ └── helpers.ts
59│ │ │
60│ │ ├── types/
61│ │ │ ├── common.types.ts
62│ │ │ └── api.types.ts
63│ │ │
64│ │ └── constants/
65│ │ ├── routes.ts
66│ │ └── config.ts
67│ │
68│ ├── layouts/ # Layout komponenty
69│ │ ├── MainLayout/
70│ │ ├── AuthLayout/
71│ │ └── DashboardLayout/
72│ │
73│ ├── pages/ # Komponenty stron (dla routingu)
74│ │ ├── HomePage/
75│ │ ├── ProductsPage/
76│ │ ├── ProductDetailPage/
77│ │ └── CartPage/
78│ │
79│ ├── context/ # Globalne konteksty
80│ │ ├── AuthContext.tsx
81│ │ ├── ThemeContext.tsx
82│ │ └── CartContext.tsx
83│ │
84│ ├── router/ # Konfiguracja routingu
85│ │ ├── routes.tsx
86│ │ └── ProtectedRoute.tsx
87│ │
88│ ├── styles/ # Globalne style
89│ │ ├── globals.css
90│ │ ├── variables.css
91│ │ └── reset.css
92│ │
93│ ├── App.tsx
94│ └── index.tsx
95│
96├── .eslintrc.js
97├── .prettierrc
98├── tsconfig.json
99├── package.json
100└── README.mdZasady organizacji plików
- Reguła 3 poziomów maksymalnie
- Unikaj głębszego zagnieżdżenia niż 3 poziomy
- Jeśli potrzebujesz więcej, prawdopodobnie twoja struktura jest za skomplikowana
1// DOBRZE - 3 poziomy
2src/features/products/components/
3
4// ŹLE - za głębokie
5src/modules/ecommerce/features/products/ui/components/- Eksportuj przez index.ts
- Każdy folder z komponentem ma index.ts
- Upraszcza importy i ukrywa szczegóły implementacji
1// components/Button/index.ts
2export { default } from './Button';
3export * from './Button.types';
4
5// Użycie
6import Button from './components/Button'; // czytelne
7// zamiast
8import Button from './components/Button/Button'; // rozwlekłe- Colocation - trzymaj blisko to, co jest używane razem
- Style obok komponentu
- Testy obok komponentu
- Typy obok komponentu
1Button/
2├── Button.tsx # Komponent
3├── Button.styles.ts # Style
4├── Button.test.tsx # Testy
5├── Button.types.ts # Typy
6└── index.ts # Eksport- Shared vs Feature-specific
- Jeśli coś jest używane w więcej niż 2 miejscach → shared
- Jeśli coś jest specyficzne dla feature → trzymaj w feature
Praktyczne wskazówki dotyczące struktury projektu
Zacznij prosto - Nie przesadzaj ze skomplikowaną strukturą na początku projektu. Dla małej aplikacji type-based może wystarczyć, dopiero później refaktoryzuj do feature-based gdy projekt urośnie.
Refaktoryzuj, gdy zajdzie potrzeba - Dostosowuj strukturę w miarę rozwoju projektu. Jeśli folder ma więcej niż 10-15 plików, rozważ jego podział.
Utrzymuj małe komponenty - Komponenty powinny być małe i skupione na jednym zadaniu. Jeśli komponent ma więcej niż 200-300 linii, rozważ jego podział.
Grupuj powiązane pliki - Trzymaj razem pliki, które są ze sobą ściśle powiązane. Jeśli zawsze edytujesz dwa pliki razem, prawdopodobnie powinny być w tym samym folderze.
Dokumentuj - Dodaj README.md do głównych katalogów, aby wyjaśnić ich przeznaczenie i strukturę.
Spójność przede wszystkim - Gdy wybierzesz układ (według typu, według funkcji albo opisaną wyżej hybrydę), trzymaj się go w całym projekcie. Najgorsze jest przypadkowe mieszanie stylów.
Narzędzia pomagające w organizacji kodu
- ESLint - Pomaga utrzymać spójny styl kodu i wyłapać potencjalne błędy
- Prettier - Automatycznie formatuje kod według ustalonych reguł
- Import sorter - Sortuje importy dla lepszej czytelności
- Path aliases - Upraszcza importy używając aliasów jak @components, @utils
1// tsconfig.json lub jsconfig.json
2{
3 "compilerOptions": {
4 "baseUrl": "src",
5 "paths": {
6 "@components/*": ["shared/components/*"],
7 "@features/*": ["features/*"],
8 "@utils/*": ["shared/utils/*"],
9 "@hooks/*": ["shared/hooks/*"]
10 }
11 }
12}
13
14// Użycie
15import Button from '@components/Button';
16import { useAuth } from '@features/auth';
17import { formatDate } from '@utils/formatDate';Dobrze zorganizowana struktura projektu znacznie ułatwia pracę, szczególnie w dużych zespołach i projektach. Pamiętaj, że nie ma jedynej "właściwej" struktury - najważniejsze, aby była spójna, logiczna dla Twojego zespołu i skalowalna wraz z rozwojem projektu.
Kod do tej lekcji: App.jsx
1import React, { useState } from 'react';
2
3// Demonstracja struktury projektu Vite + React
4function ViteProjectDemo() {
5 const [activeFile, setActiveFile] = useState('App.jsx');
6
7 const fileStructure = [
8 { name: 'node_modules/', type: 'folder', description: 'Zainstalowane pakiety' },
9 { name: 'public/', type: 'folder', description: 'Pliki statyczne' },
10 { name: ' vite.svg', type: 'file', description: 'Logo Vite' },
11 { name: 'src/', type: 'folder', description: 'Kod źródłowy' },
12 { name: ' assets/', type: 'folder', description: 'Zasoby (obrazy, fonty)' },
13 { name: ' App.jsx', type: 'file', description: 'Główny komponent', active: true },
14 { name: ' App.css', type: 'file', description: 'Style komponentu' },
15 { name: ' main.jsx', type: 'file', description: 'Punkt wejściowy' },
16 { name: ' index.css', type: 'file', description: 'Style globalne' },
17 { name: 'index.html', type: 'file', description: 'Główny HTML (w katalogu głównym!)' },
18 { name: 'vite.config.js', type: 'file', description: 'Konfiguracja Vite' },
19 { name: 'package.json', type: 'file', description: 'Konfiguracja projektu' },
20 ];
21
22 const fileContents = {
23 'App.jsx': `import { useState } from 'react'
24import './App.css'
25
26function App() {
27 const [count, setCount] = useState(0)
28
29 return (
30 <>
31 <h1>Vite + React</h1>
32 <div className="card">
33 <button onClick={() => setCount(c => c + 1)}>
34 count is {count}
35 </button>
36 </div>
37 </>
38 )
39}
40
41export default App`,
42 'main.jsx': `import React from 'react'
43import ReactDOM from 'react-dom/client'
44import App from './App.jsx'
45import './index.css'
46
47ReactDOM.createRoot(
48 document.getElementById('root')
49).render(
50 <React.StrictMode>
51 <App />
52 </React.StrictMode>,
53)`,
54 'vite.config.js': `import { defineConfig } from 'vite'
55import react from '@vitejs/plugin-react'
56
57export default defineConfig({
58 plugins: [react()],
59})`,
60 'package.json': `{
61 "name": "moja-aplikacja",
62 "version": "0.0.0",
63 "type": "module",
64 "scripts": {
65 "dev": "vite",
66 "build": "vite build",
67 "preview": "vite preview"
68 },
69 "dependencies": {
70 "react": "^18.2.0",
71 "react-dom": "^18.2.0"
72 },
73 "devDependencies": {
74 "@vitejs/plugin-react": "^4.2.0",
75 "vite": "^5.0.0"
76 }
77}`
78 };
79
80 return (
81 <div style={{
82 fontFamily: 'Arial, sans-serif',
83 maxWidth: '1000px',
84 margin: '0 auto',
85 padding: '20px'
86 }}>
87 <header style={{
88 background: 'linear-gradient(135deg, #61dafb 0%, #21a1f1 100%)',
89 padding: '30px',
90 borderRadius: '12px',
91 color: 'white',
92 textAlign: 'center',
93 marginBottom: '30px'
94 }}>
95 <h1 style={{ margin: 0, fontSize: '2rem' }}>Vite + React</h1>
96 <p style={{ margin: '10px 0 0 0', opacity: 0.9 }}>
97 Struktura projektu i podstawowe pliki
98 </p>
99 </header>
100
101 <div style={{
102 backgroundColor: '#1e1e1e',
103 borderRadius: '8px',
104 padding: '20px',
105 marginBottom: '30px',
106 fontFamily: 'monospace'
107 }}>
108 <div style={{ color: '#888', marginBottom: '10px' }}>Terminal:</div>
109 <div style={{ color: '#00ff00' }}>$ npm create vite@latest moja-aplikacja -- --template react</div>
110 <div style={{ color: '#888', marginTop: '5px' }}>Scaffolding project in /moja-aplikacja...</div>
111 <div style={{ color: '#00ff00', marginTop: '5px' }}>Done. Now run: cd moja-aplikacja && npm install && npm run dev</div>
112 </div>
113
114 <div style={{ display: 'grid', gridTemplateColumns: '300px 1fr', gap: '20px' }}>
115 <div style={{
116 backgroundColor: '#252526',
117 borderRadius: '8px',
118 padding: '15px'
119 }}>
120 <h3 style={{ color: '#cccccc', margin: '0 0 15px 0', fontSize: '14px' }}>
121 EXPLORER
122 </h3>
123 {fileStructure.map((item, index) => (
124 <div
125 key={index}
126 onClick={() => item.type === 'file' && setActiveFile(item.name.trim())}
127 style={{
128 padding: '8px 10px',
129 color: item.type === 'folder' ? '#dcb67a' : '#9cdcfe',
130 cursor: item.type === 'file' ? 'pointer' : 'default',
131 backgroundColor: activeFile === item.name.trim() ? '#094771' : 'transparent',
132 borderRadius: '4px',
133 fontSize: '14px',
134 fontFamily: 'monospace'
135 }}
136 >
137 {item.type === 'folder' ? '▸' : '•'} {item.name}
138 </div>
139 ))}
140 </div>
141
142 <div style={{
143 backgroundColor: '#1e1e1e',
144 borderRadius: '8px',
145 padding: '20px'
146 }}>
147 <div style={{
148 color: '#888',
149 fontSize: '12px',
150 marginBottom: '10px',
151 borderBottom: '1px solid #333',
152 paddingBottom: '10px'
153 }}>
154 {activeFile}
155 </div>
156 <pre style={{
157 color: '#d4d4d4',
158 margin: 0,
159 fontSize: '14px',
160 lineHeight: '1.5',
161 overflow: 'auto'
162 }}>
163 {fileContents[activeFile] || '// Wybierz plik z listy'}
164 </pre>
165 </div>
166 </div>
167
168 <div style={{
169 marginTop: '30px',
170 padding: '20px',
171 backgroundColor: '#fff3e0',
172 borderRadius: '8px'
173 }}>
174 <h3 style={{ color: '#e65100', marginTop: 0 }}>Komendy startowe</h3>
175 <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '15px' }}>
176 <div style={{ backgroundColor: 'white', padding: '15px', borderRadius: '8px' }}>
177 <code style={{ color: '#e65100' }}>npm run dev</code>
178 <p style={{ margin: '5px 0 0 0', fontSize: '14px', color: '#666' }}>
179 Uruchamia serwer deweloperski
180 </p>
181 </div>
182 <div style={{ backgroundColor: 'white', padding: '15px', borderRadius: '8px' }}>
183 <code style={{ color: '#e65100' }}>npm run build</code>
184 <p style={{ margin: '5px 0 0 0', fontSize: '14px', color: '#666' }}>
185 Buduje wersję produkcyjną
186 </p>
187 </div>
188 </div>
189 </div>
190 </div>
191 );
192}
193
194export default function App() {
195 return <ViteProjectDemo />;
196}Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Jaki jest główny cel folderu src/ w projekcie React?
2. W którym folderze znajdują się główne pliki źródłowe React?
3. Gdzie w projekcie React utworzonym z Vite znajduje się plik index.html?
Zadania praktyczne w grze
- Układanie w pionie
Ułóż hierarchię plików aplikacji React:
- Klikanie w kolejności
Ułóż workflow developmentu React:
- Edytor kodu
Stwórz w pliku App.jsx podstawową strukturę komponentu: import React, komponent funkcyjny App zwracający JSX i eksport domyślny (export default).