Dobrze zorganizowana struktura projektu jest kluczowa dla utrzymania kodu, łatwej nawigacji i skalowalności aplikacji React. W tym module przyjrzymy się najlepszym praktykom strukturyzowania projektów React i zrozumiemy, jak organizować pliki i komponenty.
Niezależnie od tego, czy używasz Create React App, Vite czy innego narzędzia, podstawowa struktura projektu React zazwyczaj wygląda podobnie:
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.js # Główny komponent aplikacji
13│ └── index.js # Punkt wejściowy aplikacji
14├── .gitignore # Pliki ignorowane przez Git
15├── package.json # Informacje o projekcie i zależności
16└── README.md # Dokumentacja projektuOmówmy najważniejsze katalogi i ich przeznaczenie:
Katalog
src/ to serce Twojej aplikacji React. Zawiera całą logikę, komponenty i zasoby. Oto jak zazwyczaj organizuje się ten katalog:Zawiera komponenty wielokrotnego użytku, które są używane w różnych częściach aplikacji. Istnieje kilka podejść do strukturyzowania komponentów:
1components/
2├── Button.jsx
3├── Button.css
4├── Header.jsx
5├── Header.css
6├── Footer.jsx
7└── Footer.css1components/
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';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.cssZawiera 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.cssFunkcje pomocnicze i narzędzia używane w całej aplikacji:
1utils/
2├── formatDate.js
3├── validation.js
4└── helpers.jsKod 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 produktamiNiestandardowe hooki React, które można używać w wielu miejscach aplikacji:
1hooks/
2├── useLocalStorage.js
3├── useFetch.js
4└── useForm.jsKonteksty React używane do zarządzania globalnym stanem:
1context/
2├── AuthContext.js
3├── ThemeContext.js
4└── CartContext.jsIstnieją dwa główne podejścia do organizacji kodu:
Pliki są grupowane według ich typu (komponenty, hooki, usługi itp.).
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.
Spójne nazewnictwo jest równie ważne jak struktura katalogów:
Button.jsx, UserProfile.jsx.jsx (nie jest to konieczne, ale pomaga w identyfikacji)useLocalStorage.js, useWindowSize.jsAuthContext.js, ThemeContext.jsapiService.js, formatDate.jsIstnieje kilka podejść do organizacji stylów w React:
1Button/
2├── Button.jsx
3└── Button.module.css1Button/
2└── Button.jsx # Zawiera definicje styled-components1Button/
2├── Button.jsx
3└── Button.scssW 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.
Dwa główne podejścia do organizacji kodu w projektach React:
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:
Wady:
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:
Wady:
Spójne nazewnictwo to kluczowy element dobrze zorganizowanego projektu. W React obowiązują następujące konwencje:
1// DOBRZE - PascalCase
2Button.jsx
3UserProfile.jsx
4ShoppingCart.jsx
5ProductCard.jsx
6
7// ZLE - inne konwencje
8button.jsx
9user-profile.jsx
10shopping_cart.jsxDlaczego PascalCase?
1// DOBRZE - camelCase z "use"
2useAuth.js
3useLocalStorage.js
4useWindowSize.js
5useProductFilters.js
6
7// ZLE - brak "use" lub zła konwencja
8Auth.js
9local-storage.js
10WindowSize.jsDlaczego "use" prefix?
1// DOBRZE - PascalCase z "Context"
2AuthContext.js
3ThemeContext.js
4CartContext.js
5UserPreferencesContext.js
6
7// ZLE - brak "Context" lub zła konwencja
8auth.js
9theme-context.js
10Cart.js1// DOBRZE - camelCase
2formatDate.js
3validateEmail.js
4apiService.js
5authService.js
6
7// ZLE - inne konwencje
8FormatDate.js
9validate-email.js
10API_Service.jsRozplanowanie lokalizacji plików w projekcie ma ogromne znaczenie dla jego czytelności i skalowalności.
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.jsFeature-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.jsJeś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.tsPołą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.md1// DOBRZE - 3 poziomy
2src/features/products/components/
3
4// ZLE - za głębokie
5src/modules/ecommerce/features/products/ui/components/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łe1Button/
2├── Button.tsx # Komponent
3├── Button.styles.ts # Style
4├── Button.test.tsx # Testy
5├── Button.types.ts # Typy
6└── index.ts # EksportZacznij 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ę.
Konsystencja przede wszystkim - Wybierz jeden styl (feature-based lub type-based) i trzymaj się go w całym projekcie. Najgorsze jest mieszanie stylów.
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.