Przejdź do głównej zawartości

Wzorcowa struktura projektu

Poniżej wzorcowa organizacja plików dla projektu grupowego ZAW:

  • Foldermy-zaw-project/
    • Folderpublic/
      • favicon.ico
    • Foldersrc/
      • Foldercomponents/
        • Folderui/
          • Button.jsx
          • Card.jsx
          • Loader.jsx
        • Folderlayout/
          • Header.jsx
          • Footer.jsx
          • Layout.jsx
        • Folderfeature/
          • ItemList.jsx
          • ItemCard.jsx
          • ItemForm.jsx
      • Folderpages/
        • HomePage.jsx
        • DetailPage.jsx
        • AboutPage.jsx
      • Folderhooks/
        • useLocalStorage.js
        • useFetch.js
        • useItems.js
      • Foldercontext/
        • AppContext.jsx
      • Folderutils/
        • helpers.js
        • validators.js
      • Folderdata/
        • mockData.js
      • App.jsx
      • main.jsx
      • index.css
    • index.html
    • package.json
    • vite.config.js
    • README.md
ElementKonwencjaPrzykład
KomponentyPascalCaseItemCard.jsx
HookscamelCase z useuseItems.js
UtilitiescamelCasehelpers.js
CSS ModulesPascalCase.module.cssItemCard.module.css
StałeUPPER_SNAKE_CASEAPI_URL
src/components/feature/ItemCard.jsx
import styles from './ItemCard.module.css';
function ItemCard({ item, onSelect }) {
return (
<div className={styles.card} onClick={() => onSelect(item.id)}>
<h3 className={styles.title}>{item.name}</h3>
<p className={styles.description}>{item.description}</p>
</div>
);
}
export default ItemCard;
src/hooks/useLocalStorage.js
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
export default useLocalStorage;
src/hooks/useFetch.js
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
if (!url) return;
const controller = new AbortController();
setLoading(true);
fetch(url, { signal: controller.signal })
.then((res) => {
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
return res.json();
})
.then((data) => {
setData(data);
setError(null);
})
.catch((err) => {
if (err.name !== 'AbortError') {
setError(err.message);
}
})
.finally(() => setLoading(false));
return () => controller.abort();
}, [url]);
return { data, loading, error };
}
export default useFetch;
src/App.jsx
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import Layout from './components/layout/Layout';
import HomePage from './pages/HomePage';
import DetailPage from './pages/DetailPage';
import NotFoundPage from './pages/NotFoundPage';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<HomePage />} />
<Route path="items/:id" element={<DetailPage />} />
<Route path="404" element={<NotFoundPage />} />
<Route path="*" element={<Navigate to="/404" replace />} />
</Route>
</Routes>
</BrowserRouter>
);
}
export default App;