Kurs JavaScript i React · Moduł 1: Podstawy React

Struktura projektu React

13 min czytania
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 projektu

Omó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.css

Struktura 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.js

Uż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.css

assets/

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.css

utils/

Funkcje pomocnicze i narzędzia używane w całej aplikacji:

1utils/
2├── formatDate.js
3├── validation.js
4└── helpers.js

services/

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 produktami

hooks/

Niestandardowe hooki React, które można używać w wielu miejscach aplikacji:

1hooks/
2├── useLocalStorage.js
3├── useFetch.js
4└── useForm.js

context/

Konteksty React używane do zarządzania globalnym stanem:

1context/
2├── AuthContext.js
3├── ThemeContext.js
4└── CartContext.js

Organizacja 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.css

Styled Components

1Button/
2└── Button.jsx  # Zawiera definicje styled-components

SCSS/SASS

1Button/
2├── Button.jsx
3└── Button.scss

Dobre 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.js

Zalety:

  • 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.jsx

Zalety:

  • Ł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.jsx

Dlaczego 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.js

Dlaczego "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.js

Utils 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.js

Gdzie 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 hook

Type-based approach:

1hooks/
2├── useAuth.js
3├── useSession.js
4├── useProducts.js
5├── useLocalStorage.js
6├── useDebounce.js
7└── useFetch.js

Utils (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ółdzielone

Type-based approach:

1utils/
2├── formatPrice.js
3├── formatDate.js
4├── validatePassword.js
5├── filterProducts.js
6├── debounce.js
7└── cloneDeep.js

Types (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.ts

Opcja 2: Scentralizowane typy:

1types/
2├── user.types.ts
3├── product.types.ts
4├── cart.types.ts
5└── api.types.ts

Opcja 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.ts

Przykł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.md

Zasady organizacji plików

  1. 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/
  1. 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
  1. 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
  1. 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

  1. 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.

  2. Refaktoryzuj, gdy zajdzie potrzeba - Dostosowuj strukturę w miarę rozwoju projektu. Jeśli folder ma więcej niż 10-15 plików, rozważ jego podział.

  3. 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ł.

  4. 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.

  5. Dokumentuj - Dodaj README.md do głównych katalogów, aby wyjaśnić ich przeznaczenie i strukturę.

  6. 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

  1. ESLint - Pomaga utrzymać spójny styl kodu i wyłapać potencjalne błędy
  2. Prettier - Automatycznie formatuje kod według ustalonych reguł
  3. Import sorter - Sortuje importy dla lepszej czytelności
  4. 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. 1. Jaki jest główny cel folderu src/ w projekcie React?

  2. 2. W którym folderze znajdują się główne pliki źródłowe React?

  3. 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).

Przydatne artykuły