在 2024 年以后的前端生态中,基于 Vite 和 React 18+ 的构建方案已成为企业级开发的主流标准。良好的目录结构不仅是代码存放的物理空间,更是软件架构思维的体现。它直接决定了项目的可维护性、扩展性以及团队协作的效率。
本人认为(仅个人观点),学习一项技术栈应该清楚地认识到,我学它的目的是什么,他能帮我解决什么问题,他的作用是什么,不要为了增加技术栈而去学习技术栈,所以当你要学习技术栈时,你应该关注于他能帮你解决什么样的技术问题,从他的定义,使用场景,和实战效果,比如下面放的React初始化项目目录结构,如果你知道了每个文件的作用,那么剩下的无非是将他们串联起来,再去逐步深入,这样你就可以对这个技术栈更加清晰并熟练地掌握,下面我们来讲讲React项目目录结构,和它们的作用。
本文将摒弃传统的 Webpack/CRA 结构,深入剖析现代 React 项目的标准工程目录。
一、工程根目录:构建与配置基石
与旧版脚手架不同,Vite 将工程配置置于核心位置,且入口机制发生了根本性变化。
1. index.html (核心入口)
含义:应用的入口页面。
专业解读:在 Vite 中,index.html 被视为源码的一部分,且必须位于项目根目录。Vite 利用它作为模块图(Module Graph)的入口点,通过
示例代码:
Html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Enterprise React App</title>
</head>
<body>
<div id="root"></div>
<!-- 指向 src 目录下的主入口文件 -->
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
2. vite.config.js
含义:Vite 的配置文件。
专业解读:用于配置插件(Plugins)、路径别名(Alias)、代理(Proxy)以及打包策略(Build Options)。
配置路径别名是最佳实践,最常见的是取为@:代表src目录,因为你之后创建的文件大部分在这个目录下,这样能有效避免 ../../../ 这种“回调地狱”式的路径引用。
示例代码:
JavaScript
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'), // 将 @ 指向 src 目录
},
},
})
3. package.json
含义:项目元数据与依赖清单。
专业解读:除了定义 dependencies (运行时依赖) 和 devDependencies (开发依赖),核心关注 scripts 字段。现代项目通常集成 lint、format 和 preview 命令。
4. .env
含义:环境变量配置。
专业解读:Vite 使用 dotenv 加载环境变量。注意,只有以 VITE_ 前缀开头的变量才会暴露给客户端代码,通过 import.meta.env 访问,而非传统的 process.env。
二、源码目录 (src):核心逻辑解构
src 是业务逻辑的载体。在 React 18 中,入口文件的写法与以往有显著不同。
1. main.jsx (应用引导)
含义:JavaScript 执行入口。
专业解读:
- 扩展名:Vite 强制要求包含 JSX 语法的文件使用 .jsx 或 .tsx 后缀。
- 并发模式:使用 React 18 的 createRoot API 替代了旧版的 ReactDOM.render,开启了并发渲染(Concurrent Mode)的能力。
- 严格模式:<React.StrictMode> 用于在开发环境下检测潜在问题(如副作用不纯)。
示例代码:
Jsx
// src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from '@/App'
import './index.css' // 全局样式重置
// 获取 DOM 节点并创建 Root 实例
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
2. App.jsx
含义:根组件。
专业解读:通常作为全局 Context Provider(如 Theme、Redux Store、Router)的挂载点,或者是应用的主布局容器。
3. assets/
含义:静态资源目录。
专业解读:存放图片、字体、SVG 等。Vite 支持在 JS 中直接 import 这些资源,并根据文件大小自动决定是内联为 Base64 还是作为独立文件打包(Asset Inlining)。
4. components/
含义:通用 UI 组件库。
专业解读:存放“哑组件”(Dumb Components)或基础原子组件(如 Button、Modal)。这些组件不应包含具体的业务逻辑,只负责 UI 渲染,通过 Props 接收数据。
三、进阶架构:企业级目录划分
随着项目复杂度提升,扁平化的目录结构已不足以支撑。我们需要基于**职责分离(Separation of Concerns)和功能特性(Feature-based)**的原则进行架构设计。
1. api/ (网络层)
作用:统一管理 HTTP 请求。
最佳实践:不要在组件内部直接调用 axios.get。应封装统一的 Request 实例(包含拦截器处理 Token 和错误),并将 API 定义为独立的模块。
示例代码:
JavaScript
// src/api/user.js
import request from '@/utils/request'
export const login = (data) => {
return request.post('/auth/login', data)
}
export const getUserInfo = () => {
return request.get('/user/profile')
}
2. hooks/ (逻辑复用层)
作用:存放自定义 Hooks。
最佳实践:将非 UI 的状态逻辑(如倒计时、滚动监听、复杂表单处理)抽离为 Hook,实现逻辑复用和组件瘦身。
示例代码:
JavaScript
// src/hooks/useFetch.js
import { useState, useEffect } from 'react'
export const useFetch = (apiFunc) => {
const [data, setData] = useState(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
apiFunc()
.then(res => setData(res))
.finally(() => setLoading(false))
}, [])
return { data, loading }
}
3. store/ (状态管理层)
作用:全局状态管理。
最佳实践:推荐使用 Redux Toolkit (RTK) 或 Zustand(更为主流)。摒弃传统的 Redux 分散式文件夹(actions/reducers),采用“Slice”模式聚合逻辑。
示例代码 (RTK Slice) :
JavaScript
// src/store/counterSlice.js
import { createSlice } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: state => { state.value += 1 },
// Immer 库允许直接修改 state
}
})
export const { increment } = counterSlice.actions
export default counterSlice.reducer
4. pages/ (视图层)
作用:页面级组件。
最佳实践:每个页面文件夹下应包含其独有的组件和样式。例如 src/pages/Home/index.jsx。页面组件负责组合 components 和调用 hooks。
5. router/ (路由配置)
作用:路由定义。
最佳实践:使用 React Router v6 的 Data Router (createBrowserRouter),将路由表抽离为配置文件,支持懒加载(Lazy Loading)。
6. utils/ (工具层)
作用:纯函数工具库。
最佳实践:存放无副作用的辅助函数,如日期格式化、数据深拷贝、正则校验等。
四、架构总结
一个优秀的 React 目录结构应当遵循以下原则:
- 单一数据源:API 请求和状态管理应集中定义,避免散落在组件中。
- 就近原则:如果一个组件只被某个页面使用,应优先放在该页面的目录下,而非全局 components。
- 模块化:利用 ES Modules 和路径别名优化引用体验。
通过采用 Vite + React 18 的现代化架构,配合上述的目录规范,可以显著降低大型项目的维护成本,使代码库在长期迭代中保持清晰与健壮。