Build maintainable, scalable React apps with Vite, clean architecture, and comprehensive testing. Follows separation of concerns, reusable components, and testability best practices.
Build maintainable, scalable React applications using Vite, clean architecture principles, Jest testing, and reusable component patterns. Optimized for fast development with HMR and production builds.
Guides you through developing React applications with:
Follow this structure for all React Vite projects:
```
/src/
/components/ # Reusable UI components (atomic, well-documented)
/features/ # Feature modules (business logic, state, API calls)
/hooks/ # Custom React hooks
/utils/ # Utility functions
/styles/ # Global and modular styles
/tests/ # Standalone test utilities/mocks (if not colocated)
/public/ # Static assets
/__mocks__/ # Jest mocks (if needed)
```
1. **Install dependencies:**
```bash
npm install
```
2. **Start development server:**
```bash
npm run dev
```
3. **Run tests:**
```bash
npm test
```
4. **Build for production:**
```bash
npm run build
```
Use this pattern for all components:
```jsx
// src/components/Button/Button.jsx
import React from "react";
import PropTypes from "prop-types";
export function Button({ children, onClick, variant = "primary" }) {
return (
<button className={`btn btn-${variant}`} onClick={onClick}>
{children}
</button>
);
}
Button.propTypes = {
children: PropTypes.node.isRequired,
onClick: PropTypes.func,
variant: PropTypes.oneOf(["primary", "secondary"]),
};
```
**Use for:** UI state, form inputs, toggles
**When:** State is only used by one component
```jsx
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
```
**Use for:** Reusable logic, API calls, complex state
**When:** Logic is shared between components
**Location:** `/src/hooks/` or `/src/features/[feature]/hooks/`
```jsx
// src/features/auth/useAuth.js
export function useAuth() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const login = useCallback(async (credentials) => {
setLoading(true);
try {
const user = await loginAPI(credentials);
setUser(user);
} finally {
setLoading(false);
}
}, []);
return { user, loading, login };
}
```
**Use for:** Theme, auth, shared configurations
**When:** State needs to be accessed by many components
**Avoid:** Frequent updates that affect many components
```jsx
// src/features/theme/ThemeContext.jsx
export const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
const toggleTheme = useCallback(() => {
setTheme((t) => (t === "light" ? "dark" : "light"));
}, []);
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
```
**Use for:** Complex global state, heavy data manipulation
**When:**
**Location:** `/src/store/` with feature-based slices
```jsx
// Button.test.jsx
import { render, screen, fireEvent } from "@testing-library/react";
import { Button } from "./Button";
test("renders button with text", () => {
render(<Button>Click me</Button>);
expect(screen.getByText("Click me")).toBeInTheDocument();
});
test("calls onClick when clicked", () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click me</Button>);
fireEvent.click(screen.getByText("Click me"));
expect(handleClick).toHaveBeenCalledTimes(1);
});
```
```jsx
import { renderHook, act } from "@testing-library/react-hooks";
import { useCounter } from "./useCounter";
test("useCounter increments count", () => {
const { result } = renderHook(() => useCounter());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
```
Include `eslint-plugin-jsx-a11y` for automated accessibility checks:
```json
{
"extends": ["plugin:jsx-a11y/recommended"]
}
```
```jsx
import { render } from "@testing-library/react";
import { axe, toHaveNoViolations } from "jest-axe";
expect.extend(toHaveNoViolations);
test("should have no accessibility violations", async () => {
const { container } = render(<MyComponent />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
```
**Dynamic Imports for Code Splitting:**
```jsx
const MyComponent = React.lazy(() => import("./MyComponent"));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
);
}
```
**Asset Handling:**
```jsx
// Static assets under /public/ are served at /
// Import assets directly for build optimization
import logo from "./assets/logo.svg";
```
**Vite Config Example:**
```js
// vite.config.js
export default defineConfig({
build: {
minify: "terser",
rollupOptions: {
output: {
manualChunks: {
vendor: ["react", "react-dom"],
},
},
},
},
resolve: {
alias: {
"@": "/src",
},
},
});
```
```bash
VITE_API_URL=https://api.example.com
```
```jsx
// Access in code
const apiUrl = import.meta.env.VITE_API_URL;
```
```bash
npm create vite@latest my-app -- --template react
cd my-app
npm install
npm install -D jest @testing-library/react @testing-library/jest-dom eslint prettier
```
Create `jest.config.js` and `src/setupTests.js` with React Testing Library setup.
Create directories: `/src/components`, `/src/features`, `/src/hooks`, `/src/utils`, `/src/styles`.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/react-vite-clean-architecture/raw