Appearance
React项目结构解析完全指南
第一章:标准项目结构
1.1 Vite项目结构详解
默认结构
my-react-app/
├── node_modules/ # 依赖包目录(不提交到Git)
├── public/ # 静态资源目录
│ └── vite.svg # 公共静态文件
├── src/ # 源代码目录
│ ├── assets/ # 资源文件(会被处理)
│ │ └── react.svg
│ ├── App.css # 应用样式
│ ├── App.jsx # 根组件
│ ├── index.css # 全局样式
│ └── main.jsx # 应用入口
├── .gitignore # Git忽略文件配置
├── index.html # HTML模板
├── package.json # 项目配置
├── package-lock.json # 依赖锁定文件
├── README.md # 项目说明
└── vite.config.js # Vite配置文件各目录详解
1. node_modules/
作用:存放所有npm依赖包
特点:
- 自动生成,不应手动修改
- 体积巨大(可达数百MB)
- 添加到.gitignore,不提交到版本控制
- 通过npm install重新生成
查看依赖:
npm list --depth=02. public/
作用:存放不需要处理的静态资源
特点:
- 文件会被原样复制到构建目录
- 通过绝对路径引用:/filename.ext
- 适合存放:favicon、robots.txt、静态HTML等
- 不会经过Vite处理(不会压缩、hash等)
使用示例:
// HTML中引用
<link rel="icon" href="/favicon.ico" />
// 组件中引用
<img src="/logo.png" alt="Logo" />3. src/
作用:应用源代码目录
特点:
- 所有代码文件都放这里
- 会被Vite处理和打包
- 支持ES6+、JSX、TypeScript等
- 可以使用路径别名(@/)
结构建议:
src/
├── components/ # 可复用组件
├── pages/ # 页面组件
├── hooks/ # 自定义Hooks
├── utils/ # 工具函数
├── services/ # API服务
├── store/ # 状态管理
├── styles/ # 样式文件
├── assets/ # 资源文件
├── constants/ # 常量定义
└── types/ # TypeScript类型定义4. src/assets/
作用:存放需要处理的资源文件
特点:
- 图片、字体、SVG等会被优化
- 小于4KB的图片会被转为base64
- 支持导入为模块
使用示例:
// 导入图片
import logo from './assets/logo.png'
<img src={logo} alt="Logo" />
// 导入SVG
import icon from './assets/icon.svg'
<img src={icon} alt="Icon" />
// 导入SVG为组件(需插件)
import { ReactComponent as Icon } from './assets/icon.svg'
<Icon />5. src/main.jsx
javascript
// 应用入口文件
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
// 创建根节点
const root = ReactDOM.createRoot(document.getElementById('root'))
// 渲染应用
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
作用:
1. 导入必要的依赖
2. 挂载React应用到DOM
3. 应用全局配置(如StrictMode)6. index.html
html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
特点:
- 位于根目录(Vite特殊之处)
- type="module" 表示ES模块
- 直接引用src中的文件
- 可以在此添加全局meta标签7. package.json
json
{
"name": "my-react-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.2.1",
"vite": "^5.0.0"
}
}
字段说明:
- name: 项目名称
- version: 版本号
- type: "module" 表示使用ES模块
- scripts: 可执行脚本
- dependencies: 生产依赖
- devDependencies: 开发依赖8. vite.config.js
javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})
作用:
- Vite构建配置
- 配置插件
- 设置别名、代理等1.2 Next.js项目结构详解
App Router结构(Next.js 13+)
my-next-app/
├── app/ # App Router目录
│ ├── layout.js # 根布局
│ ├── page.js # 首页
│ ├── loading.js # 加载UI
│ ├── error.js # 错误处理
│ ├── not-found.js # 404页面
│ ├── globals.css # 全局样式
│ ├── api/ # API路由
│ │ └── hello/
│ │ └── route.js
│ ├── (marketing)/ # 路由组
│ │ ├── about/
│ │ │ └── page.js
│ │ └── contact/
│ │ └── page.js
│ └── blog/ # 嵌套路由
│ ├── layout.js
│ ├── page.js
│ └── [slug]/
│ └── page.js
├── components/ # 共享组件
├── lib/ # 工具函数
├── public/ # 静态资源
├── .env.local # 环境变量
├── next.config.js # Next.js配置
├── package.json
└── tsconfig.json特殊文件说明
layout.js - 布局
javascript
// app/layout.js
export default function RootLayout({ children }) {
return (
<html lang="zh-CN">
<body>
<header>导航栏</header>
<main>{children}</main>
<footer>页脚</footer>
</body>
</html>
)
}
特点:
- 共享UI布局
- 可以嵌套
- 保持状态(不重新渲染)page.js - 页面
javascript
// app/page.js
export default function Home() {
return <h1>首页</h1>
}
// app/about/page.js
export default function About() {
return <h1>关于我们</h1>
}
特点:
- 定义路由页面
- 自动生成路由loading.js - 加载状态
javascript
// app/loading.js
export default function Loading() {
return <div>加载中...</div>
}
特点:
- 自动显示在Suspense边界内
- 页面加载时显示error.js - 错误处理
javascript
// app/error.js
'use client'
export default function Error({ error, reset }) {
return (
<div>
<h2>出错了!</h2>
<p>{error.message}</p>
<button onClick={reset}>重试</button>
</div>
)
}
特点:
- 必须是Client Component
- 捕获错误边界route.js - API路由
javascript
// app/api/hello/route.js
export async function GET(request) {
return Response.json({ message: 'Hello' })
}
export async function POST(request) {
const body = await request.json()
return Response.json({ received: body })
}
特点:
- 定义API端点
- 支持所有HTTP方法第二章:推荐的项目结构
2.1 小型项目结构
适用于:简单应用、学习项目、MVP
src/
├── components/ # 组件
│ ├── Button.jsx
│ ├── Card.jsx
│ └── Header.jsx
├── pages/ # 页面
│ ├── Home.jsx
│ ├── About.jsx
│ └── Contact.jsx
├── App.jsx # 根组件
├── main.jsx # 入口
├── index.css # 全局样式
└── App.css # 应用样式2.2 中型项目结构
适用于:常规业务应用
src/
├── components/ # 可复用组件
│ ├── common/ # 通用组件
│ │ ├── Button/
│ │ │ ├── Button.jsx
│ │ │ └── Button.css
│ │ ├── Input/
│ │ └── Modal/
│ └── layout/ # 布局组件
│ ├── Header.jsx
│ ├── Footer.jsx
│ └── Sidebar.jsx
├── pages/ # 页面组件
│ ├── Home/
│ │ ├── Home.jsx
│ │ └── Home.css
│ ├── About/
│ └── Dashboard/
├── hooks/ # 自定义Hooks
│ ├── useAuth.js
│ ├── useFetch.js
│ └── useLocalStorage.js
├── services/ # API服务
│ ├── api.js
│ ├── auth.js
│ └── users.js
├── utils/ # 工具函数
│ ├── format.js
│ ├── validate.js
│ └── constants.js
├── styles/ # 样式文件
│ ├── variables.css
│ ├── reset.css
│ └── global.css
├── App.jsx
└── main.jsx2.3 大型项目结构
适用于:企业级应用、复杂系统
src/
├── features/ # 功能模块(按业务划分)
│ ├── auth/
│ │ ├── components/
│ │ │ ├── LoginForm.jsx
│ │ │ └── RegisterForm.jsx
│ │ ├── hooks/
│ │ │ └── useAuth.js
│ │ ├── services/
│ │ │ └── authService.js
│ │ ├── store/
│ │ │ └── authSlice.js
│ │ └── index.js
│ ├── user/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── services/
│ │ └── index.js
│ └── products/
│ ├── components/
│ ├── hooks/
│ └── index.js
├── shared/ # 共享资源
│ ├── components/ # 通用组件
│ │ ├── ui/
│ │ │ ├── Button/
│ │ │ ├── Input/
│ │ │ └── Modal/
│ │ └── layout/
│ ├── hooks/ # 通用Hooks
│ ├── utils/ # 工具函数
│ ├── constants/ # 常量
│ ├── types/ # TypeScript类型
│ └── styles/ # 全局样式
├── core/ # 核心功能
│ ├── api/ # API配置
│ │ ├── axios.js
│ │ └── endpoints.js
│ ├── router/ # 路由配置
│ │ └── routes.jsx
│ ├── store/ # 状态管理
│ │ └── index.js
│ └── config/ # 应用配置
│ └── app.config.js
├── assets/ # 静态资源
│ ├── images/
│ ├── fonts/
│ └── icons/
├── App.jsx
└── main.jsx2.4 文件命名规范
组件文件
推荐:
- PascalCase: Button.jsx, UserProfile.jsx
- 文件名与组件名一致
文件结构:
Button/
├── Button.jsx # 组件
├── Button.test.jsx # 测试
├── Button.css # 样式
└── index.js # 导出
或:
Button.jsx
Button.test.jsx
Button.module.css工具函数
推荐:
- camelCase: formatDate.js, validateEmail.js
示例:
utils/
├── formatDate.js
├── validateEmail.js
└── index.js # 统一导出常量文件
推荐:
- 大写加下划线: API_ENDPOINTS.js, USER_ROLES.js
示例:
constants/
├── API_ENDPOINTS.js
├── USER_ROLES.js
└── index.jsHooks文件
推荐:
- use前缀 + camelCase: useAuth.js, useFetch.js
示例:
hooks/
├── useAuth.js
├── useFetch.js
├── useLocalStorage.js
└── index.js第三章:按功能组织(推荐)
3.1 Feature-based结构
按业务功能划分,每个功能模块包含相关的所有代码:
src/
├── features/
│ ├── auth/
│ │ ├── components/
│ │ │ ├── LoginForm.jsx
│ │ │ ├── RegisterForm.jsx
│ │ │ └── PasswordReset.jsx
│ │ ├── hooks/
│ │ │ ├── useAuth.js
│ │ │ └── useAuthValidation.js
│ │ ├── services/
│ │ │ └── authService.js
│ │ ├── store/
│ │ │ └── authSlice.js
│ │ ├── utils/
│ │ │ └── tokenHelper.js
│ │ ├── types/
│ │ │ └── auth.types.ts
│ │ └── index.js
│ │
│ ├── products/
│ │ ├── components/
│ │ │ ├── ProductList.jsx
│ │ │ ├── ProductCard.jsx
│ │ │ ├── ProductDetail.jsx
│ │ │ └── ProductFilter.jsx
│ │ ├── hooks/
│ │ │ ├── useProducts.js
│ │ │ └── useProductFilter.js
│ │ ├── services/
│ │ │ └── productService.js
│ │ └── index.js
│ │
│ └── cart/
│ ├── components/
│ ├── hooks/
│ └── index.js优点:
- 高内聚:相关代码集中
- 易维护:修改功能影响范围小
- 可移植:功能模块可以独立迁移
- 清晰:业务逻辑一目了然
3.2 导出策略
每个feature通过index.js统一导出:
javascript
// features/auth/index.js
export { default as LoginForm } from './components/LoginForm'
export { default as RegisterForm } from './components/RegisterForm'
export { useAuth } from './hooks/useAuth'
export { authService } from './services/authService'
// 使用时:
import { LoginForm, useAuth } from '@/features/auth'3.3 共享代码组织
src/
├── shared/
│ ├── components/ # UI组件库
│ │ ├── Button/
│ │ ├── Input/
│ │ ├── Modal/
│ │ ├── Table/
│ │ └── index.js
│ │
│ ├── hooks/ # 通用Hooks
│ │ ├── useDebounce.js
│ │ ├── useLocalStorage.js
│ │ ├── useMediaQuery.js
│ │ └── index.js
│ │
│ ├── utils/ # 工具函数
│ │ ├── format/
│ │ │ ├── date.js
│ │ │ ├── number.js
│ │ │ └── string.js
│ │ ├── validate/
│ │ │ ├── email.js
│ │ │ └── phone.js
│ │ └── index.js
│ │
│ └── constants/ # 常量
│ ├── api.js
│ ├── routes.js
│ └── index.js第四章:样式组织
4.1 CSS Modules
组件目录结构:
Button/
├── Button.jsx
├── Button.module.css
└── index.js
使用:
// Button.jsx
import styles from './Button.module.css'
function Button({ children }) {
return (
<button className={styles.button}>
{children}
</button>
)
}
// Button.module.css
.button {
padding: 10px 20px;
background-color: blue;
color: white;
}4.2 Styled Components
javascript
// Button/Button.jsx
import styled from 'styled-components'
const StyledButton = styled.button`
padding: 10px 20px;
background-color: ${props => props.primary ? 'blue' : 'gray'};
color: white;
`
function Button({ primary, children }) {
return (
<StyledButton primary={primary}>
{children}
</StyledButton>
)
}4.3 Tailwind CSS
javascript
// Button.jsx
function Button({ variant = 'primary', children }) {
const baseClasses = 'px-4 py-2 rounded font-medium'
const variantClasses = {
primary: 'bg-blue-500 text-white hover:bg-blue-600',
secondary: 'bg-gray-500 text-white hover:bg-gray-600'
}
return (
<button className={`${baseClasses} ${variantClasses[variant]}`}>
{children}
</button>
)
}4.4 全局样式组织
styles/
├── base/ # 基础样式
│ ├── reset.css # 重置样式
│ ├── variables.css # CSS变量
│ └── typography.css # 字体样式
├── components/ # 组件样式(如果不用CSS Modules)
│ ├── button.css
│ └── modal.css
├── utilities/ # 工具类
│ └── helpers.css
└── index.css # 主样式文件(导入所有)第五章:路径别名配置
5.1 Vite配置
javascript
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@pages': path.resolve(__dirname, './src/pages'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
'@services': path.resolve(__dirname, './src/services'),
'@assets': path.resolve(__dirname, './src/assets'),
'@styles': path.resolve(__dirname, './src/styles')
}
}
})5.2 TypeScript配置
json
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@pages/*": ["src/pages/*"],
"@hooks/*": ["src/hooks/*"],
"@utils/*": ["src/utils/*"],
"@services/*": ["src/services/*"],
"@assets/*": ["src/assets/*"],
"@styles/*": ["src/styles/*"]
}
}
}5.3 使用示例
javascript
// 不使用别名(相对路径)
import Button from '../../../components/common/Button'
import { formatDate } from '../../../utils/format'
import logo from '../../../assets/logo.png'
// 使用别名
import Button from '@components/common/Button'
import { formatDate } from '@utils/format'
import logo from '@assets/logo.png'第六章:环境变量管理
6.1 环境变量文件
项目根目录:
.env # 所有环境通用
.env.local # 本地覆盖(不提交Git)
.env.development # 开发环境
.env.production # 生产环境
.env.test # 测试环境6.2 Vite环境变量
bash
# .env
VITE_APP_TITLE=My React App
VITE_APP_VERSION=1.0.0
# .env.development
VITE_API_URL=http://localhost:8080/api
VITE_DEBUG=true
# .env.production
VITE_API_URL=https://api.production.com
VITE_DEBUG=false使用:
javascript
// 在代码中访问
const apiUrl = import.meta.env.VITE_API_URL
const appTitle = import.meta.env.VITE_APP_TITLE
const isDev = import.meta.env.DEV
const isProd = import.meta.env.PROD
console.log('API URL:', apiUrl)
console.log('Mode:', import.meta.env.MODE)注意:
- 必须以
VITE_开头才能暴露给客户端 - 使用
import.meta.env访问 - 重启dev server后生效
6.3 Next.js环境变量
bash
# .env.local
DATABASE_URL=postgresql://...
SECRET_KEY=your-secret-key
# 暴露给浏览器的变量(以NEXT_PUBLIC_开头)
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX使用:
javascript
// 服务器端可访问所有变量
const dbUrl = process.env.DATABASE_URL
const secretKey = process.env.SECRET_KEY
// 客户端只能访问NEXT_PUBLIC_前缀的变量
const apiUrl = process.env.NEXT_PUBLIC_API_URL6.4 配置文件组织
javascript
// src/config/app.config.js
export const appConfig = {
appName: import.meta.env.VITE_APP_TITLE || 'My App',
apiUrl: import.meta.env.VITE_API_URL,
apiTimeout: 10000,
pageSize: 20,
// 功能开关
features: {
enableAuth: true,
enableAnalytics: import.meta.env.PROD,
enableDebug: import.meta.env.DEV
},
// API端点
endpoints: {
login: '/auth/login',
register: '/auth/register',
users: '/users',
products: '/products'
}
}
// 使用
import { appConfig } from '@/config/app.config'
console.log(appConfig.apiUrl)第七章:代码组织最佳实践
7.1 单一职责原则
每个文件/组件只做一件事:
javascript
// 不好:一个文件包含多个组件
function UserList() { /* ... */ }
function UserCard() { /* ... */ }
function UserAvatar() { /* ... */ }
// 好:每个组件单独文件
// UserList.jsx
export default function UserList() { /* ... */ }
// UserCard.jsx
export default function UserCard() { /* ... */ }
// UserAvatar.jsx
export default function UserAvatar() { /* ... */ }7.2 合理的组件大小
建议:
- 每个文件不超过300行
- 每个组件不超过200行
- 超过则拆分
拆分策略:
1. 提取子组件
2. 提取自定义Hook
3. 提取工具函数7.3 导入顺序规范
javascript
// 1. 外部依赖
import React, { useState, useEffect } from 'react'
import { BrowserRouter } from 'react-router-dom'
import axios from 'axios'
// 2. 内部依赖(绝对路径)
import Button from '@/components/Button'
import { useAuth } from '@/hooks/useAuth'
import { apiService } from '@/services/api'
// 3. 相对路径导入
import Header from './Header'
import './App.css'
// 4. 类型导入(TypeScript)
import type { User } from '@/types/user'7.4 导出规范
javascript
// 命名导出(推荐用于工具函数)
export function formatDate() {}
export function formatNumber() {}
// 默认导出(推荐用于组件)
export default function Button() {}
// 混合导出
export function helper() {}
export default function Component() {}
// index.js统一导出
export { default as Button } from './Button'
export { default as Input } from './Input'
export * from './utils'第八章:不同类型项目的结构
8.1 SPA项目结构
src/
├── components/
├── pages/
├── hooks/
├── services/
├── store/ # 状态管理
│ ├── slices/
│ └── index.js
├── router/ # 路由配置
│ ├── routes.jsx
│ └── guards.js
└── App.jsx8.2 SSR项目结构(Next.js)
app/ # App Router
├── (auth)/ # 路由组
├── (dashboard)/
├── api/
└── layout.js
components/
lib/
├── server/ # 服务端工具
└── client/ # 客户端工具
public/8.3 组件库项目结构
src/
├── components/
│ ├── Button/
│ │ ├── Button.jsx
│ │ ├── Button.test.jsx
│ │ ├── Button.stories.jsx
│ │ └── index.js
│ ├── Input/
│ └── index.js
├── theme/
│ └── tokens.js
├── utils/
└── index.js # 主导出8.4 Monorepo项目结构
packages/
├── web/ # Web应用
│ ├── src/
│ └── package.json
├── mobile/ # 移动端
│ ├── src/
│ └── package.json
├── shared/ # 共享代码
│ ├── components/
│ ├── hooks/
│ └── package.json
└── admin/ # 管理后台
├── src/
└── package.json
package.json # 根配置
pnpm-workspace.yaml # Workspace配置第九章:配置文件详解
9.1 .gitignore
gitignore
# 依赖
node_modules/
.pnp/
.pnp.js
# 测试
coverage/
*.lcov
# 生产构建
dist/
build/
.next/
out/
# 开发
.DS_Store
*.log
.env.local
.env.*.local
# 编辑器
.vscode/
.idea/
*.swp
*.swo
# 其他
.cache/
.temp/9.2 .eslintrc.json
json
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended"
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"react/react-in-jsx-scope": "off",
"react/prop-types": "off"
},
"settings": {
"react": {
"version": "detect"
}
}
}9.3 .prettierrc
json
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80,
"bracketSpacing": true,
"arrowParens": "avoid"
}9.4 .editorconfig
ini
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false第十章:实战案例
10.1 电商项目结构
src/
├── features/
│ ├── products/
│ │ ├── components/
│ │ │ ├── ProductList.jsx
│ │ │ ├── ProductCard.jsx
│ │ │ ├── ProductDetail.jsx
│ │ │ └── ProductFilter.jsx
│ │ ├── hooks/
│ │ │ ├── useProducts.js
│ │ │ └── useProductSearch.js
│ │ └── services/
│ │ └── productService.js
│ │
│ ├── cart/
│ │ ├── components/
│ │ │ ├── CartDrawer.jsx
│ │ │ ├── CartItem.jsx
│ │ │ └── CartSummary.jsx
│ │ ├── hooks/
│ │ │ └── useCart.js
│ │ └── store/
│ │ └── cartSlice.js
│ │
│ ├── checkout/
│ └── user/
│
├── shared/
│ ├── components/ui/
│ ├── hooks/
│ └── utils/
│
└── core/
├── api/
├── router/
└── store/10.2 后台管理系统结构
src/
├── layouts/
│ ├── DashboardLayout.jsx
│ ├── AuthLayout.jsx
│ └── BlankLayout.jsx
│
├── pages/
│ ├── Dashboard/
│ ├── Users/
│ ├── Products/
│ └── Settings/
│
├── components/
│ ├── common/
│ ├── charts/
│ └── tables/
│
├── hooks/
│ ├── useAuth.js
│ ├── usePermission.js
│ └── useTable.js
│
├── services/
│ ├── api.js
│ ├── auth.js
│ └── users.js
│
└── config/
├── menu.config.js
└── routes.config.js总结
本章详细介绍了React项目结构:
- 标准结构:Vite和Next.js的默认结构
- 推荐结构:小、中、大型项目的组织方式
- Feature-based:按功能模块组织(推荐)
- 样式组织:CSS Modules、Styled Components、Tailwind
- 路径别名:简化导入路径
- 环境变量:配置管理
- 最佳实践:代码组织规范
- 项目类型:SPA、SSR、组件库、Monorepo
- 配置文件:Git、ESLint、Prettier
- 实战案例:电商、后台管理系统
合理的项目结构能够:
- 提高开发效率
- 降低维护成本
- 便于团队协作
- 支持项目扩展
下一章我们将学习JSX语法规则。