React 项目架构基础

45 阅读4分钟

React 项目架构基础

在现代前端开发中,React 项目早已不只是“写几个组件”这么简单。一个清晰、可扩展的项目架构,决定了开发效率、维护成本以及后期演进能力。本文将结合 Vite + React + React Router 的实际代码,梳理 React 项目的基础架构。


一、项目初始化与脚手架选择

1. 使用 Vite 初始化项目

  • npm init vite: 使用 Vite 作为项目初始化工具,Vite 是一个现代前端构建工具,支持快速冷启动(cold start)和 ESM(ECMAScript Modules)模块化。Vite 专注于开发阶段的快速迭代,内置了对 React 的支持。

  • 从 GitHub 拉取项目模板: 通过 GitHub 下载预配置的项目模板,以加速项目启动,避免从零搭建。

  • npm run dev: 运行开发服务器,启动开发模式(dev),用于本地调试和热重载(hot module replacement)。

Vite 是当前主流的前端构建工具之一,它的核心优势在于:

  • 基于 ESM(ECMAScript Modules) 的模块加载
  • 天然适配 React、Vue 等现代框架

Vite 更关注 开发阶段的效率,通过按需加载模块,避免传统打包工具在启动时的全量编译。

2. 项目开发的生命周期

一个典型的前端项目通常经历以下阶段:

  • dev(开发阶段) :本地调试、热更新
  • test(测试阶段) :单元测试、集成测试
  • production(生产阶段) :构建优化后的代码并部署上线

整体呈现一个不断迭代的循环:

dev → test → production → dev → …


二、依赖管理与模块化规范

1. devDependencies 与 dependencies

  • devDependencies(开发依赖)

    • 只在开发期间使用

    • 示例:

      • vite:开发脚手架
      • stylus:CSS 预处理器(由 Vite 自动编译)
npm i -D stylus
  • dependencies(项目依赖)

    • 项目运行时必须存在

    • 核心依赖:

      • react@19.2.0
      • react-dom@19.2.0

React 负责组件与状态逻辑,React DOM 负责将组件渲染到浏览器 DOM,可以类比为:

Vue ≈ React(核心) + React DOM(渲染层)

2. 模块化标准

  • ESM(推荐)

    • import / export
    • 支持 Tree Shaking、按需加载
  • CJS(旧标准)

    • require / module.exports
    • 常见于 Node.js 早期生态

Vite 默认采用 ESM,这是实现极速启动的重要基础。


三、前端路由管理:React Router

1. 安装路由库

npm i react-router-dom

React Router 是 React 生态中事实上的路由标准。

2. 路由模式选择

  • BrowserRouter

    • 基于 HTML5 History API
    • URL 干净(如 /about
    • 需要后端支持 SPA 路由回退
  • HashRouter

    • 使用 #/about
    • 兼容性好
    • URL 形式较早期、略显冗余
import { BrowserRouter as Router } from 'react-router-dom'

as 用于起别名,提升可读性。

3. 路由核心组件

  • Router:路由接管入口
  • Routes:路由规则总管
  • Route:单个路由实例
  • Link:替代 <a> 的导航组件(避免页面刷新)

四、入口文件与应用挂载流程

1. main.jsx:项目入口文件

import { createRoot } from 'react-dom/client'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  <App />
)
  • createRoot:React 18+ 引入的并发渲染入口
  • render:将 React 组件树挂载到真实 DOM

在开发模式下,React 会执行两次渲染,用于 StrictMode 的安全审查(review)


五、App 根组件,包裹路由和导航

import { BrowserRouter as Router, Link } from 'react-router-dom'
import AppRouters from './router'

function App() {
  return (
    <Router>
      <nav>
        <ul>
          <li><Link to="/Home">Home</Link></li>
          <li><Link to="/About">About</Link></li>
        </ul>
      </nav>

      <AppRouters />
    </Router>
  )
}

export default App

关键点:

  • <a> 标签不再直接使用,否则会触发页面刷新
  • Link 内部通过路由系统“消化跳转”
  • App 作为根组件,负责导航与路由容器

六、路由配置拆分:router/index.jsx

import { Routes, Route } from 'react-router-dom'
import Home from '../pages/Home'
import About from '../pages/About'

export default function AppRouters() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="about" element={<About />} />
    </Routes>
  )
}

这种拆分方式可以让:

  • 路由逻辑独立于 UI
  • 项目结构更加清晰
  • 后期更容易做权限路由、懒加载

七、页面组件与 Hooks 使用

1. 函数组件是 React 的主流形式

const About = () => {
    return (
        <div>
            <h1>About</h1>
        </div>
    )
}
// esm
export default About

2. Hooks:组件能力的来源

useState —— 响应式状态
const [repos, setRepos] = useState([])

类似于 Vue 的 ref / reactive

useEffect —— 副作用管理
useEffect(() => {
  fetch('https://api.github.com/users/.../repos')
    .then(res => res.json())
    .then(data => setRepos(data))
}, [])    //useEffect(() => { ... }, []) 中的 [](空依赖数组)正是为了确保副作用函数只运行一次,并且这个**一次**具体发生在组件首次挂载(mount)完成后,这与 Vue 中的 onMounted 生命周期钩子完全等价。
  • 在组件渲染完成后执行

  • 常用于:

    • 请求接口
    • 订阅 / 清理资源

render 永远是第一位的,副作用不会阻塞渲染。


八、条件渲染与列表渲染

 
    return (
        <div>
            <h1>Home</h1>
            {
                repos.length ? (
                    <ul>
                      {
                        repos.map(repo => (
                            <li key={repo.id}>
                                <a href={repo.html_url} target="_blank" rel="noreferrer">
                                    {repo.name}
                                </a>
                            </li>
                        ))
                      }  
                    </ul>
                ) : (
                    <p>暂无仓库</p>
                )
            }
        </div>
    )
}
  • 条件渲染:三元表达式
  • 列表渲染:map
  • key:用于提升 React Diff 算法性能