Java后端视角快速上手React框架——2.深入src目录,用SpringBoot思维读懂启动与路由配置blog·2026.04.13
好的看完了前面的配置文件今天review下一层先给大家看一下src目录的整体结构对应下图从外向内先讲看得到的文件main.tsx项目启动文件import { createRoot } from react-dom/client;// 1. 导入 React 渲染核心工具 import App from ./app/App.tsx;// 2. 导入项目的根组件所有页面的爹 import ./styles/index.css;// 3. 导入全局样式 // 4. 把根组件挂载到 HTML 里启动项目 createRoot(document.getElementById(root)!).render(App /);这个文件是整个React项目的启动入口和我们Java中SpringBoot的启动类功能完全一样都是用来启动整个项目的。导入相关依赖的代码比较简单这里就不详细说了重点看最核心的启动代码createRoot(document.getElementById(root)!).render(App /);这段代码有点抽象我们拆开来一步步看就很好理解了// 找到 HTML 里的容器 const container document.getElementById(root); // 创建根节点 → 把根组件 App 渲染进去 const root createRoot(container); root.render(App /);上一篇文章中说过在index.html文件中定义了id为root的盒子const container document.getElementById(root);讲盒子取出再通过root.render();将组件渲染进去整个过程完全可以类比我们Java中SpringBoot的启动类public class MyBlogRefractApplication { public static void main(String[] args) { SpringApplication.run(MyBlogRefractApplication.class, args); } }App.tsx根组件/全局配置组件import { RouterProvider } from react-router;// 导入路由页面跳转管理器 import { useEffect } from react;// React 钩子执行初始化逻辑 import { Toaster } from sonner;// 消息提示组件 import { router } from ./routes;// 路由配置文件所有页面地址 import { ErrorBoundary } from ./components/ErrorBoundary;// 错误边界全局异常捕获 function App() { useEffect(() { document.documentElement.classList.add(dark); }, []); return ( ErrorBoundary RouterProvider router{router} / Toaster themedark richColors positiontop-center closeButton / /ErrorBoundary ); } export default App;这个组件是整个React项目的根组件相当于我们Java中的全局配置类负责初始化全局逻辑、配置全局组件。我们重点讲两个核心部分1. useEffect 钩子函数useEffect(() { }, [])这是React中处理“副作用”的核心钩子简单说就是用来执行和组件渲染无关但必须执行的初始化逻辑。() { }里面写要执行的核心逻辑这里是给整个项目开启深色模式[]控制钩子的执行时机——空数组表示只执行一次项目启动时执行如果传变量比如 [count, a, b]只有这些变量变化时钩子才会重新执行注意不建议不填[]即 useEffect(() { })会导致每次组件渲染都执行造成性能浪费。这个钩子的作用我们后端同学很好理解相当于Vue中的 onMounted((){})或者Java常用框架中的 PostConstruct严格来说是PostConstruct初始化 PreDestroy资源清理的组合若钩子包含return清理函数则完全对应仅初始化则对应PostConstruct。2. 返回的全局组件结构return ( ErrorBoundary RouterProvider router{router} / Toaster themedark richColors positiontop-center closeButton / /ErrorBoundary );这段代码返回了整个项目的基础UI结构配置了三个核心全局组件类比Java中的全局配置类类名随便写的dogeConfiguration public class GlobalConfig { // 等同于 ErrorBoundary 错误捕获 Bean public GlobalExceptionHandler globalExceptionHandler() { return new GlobalExceptionHandler(); } // 等同于 RouterProvider 路由 Bean public RouterProvider routerProvider() { return new RouterProvider(); } // 等同于 Toaster 全局消息提示 Bean public Toaster toaster() { return new Toaster(); } }总的来说RouterProvider 负责页面跳转Toaster 负责全局消息提示ErrorBoundary 负责捕获全局错误三、routes.ts路由配置文件import {createBrowserRouter} from react-router; ......... import {RequireAdmin} from ./components/RequireAdmin; const routerBasename getRouterBasename(); export const router createBrowserRouter( [ { path: /, Component: Layout, children: [ {index: true, Component: Home}, {path: about, Component: About}, {path: blog, Component: BlogFeedPage}, {path: lab, Component: Lab}, {path: category/:id, Component: CategoryPage}, {path: post/:id, Component: PostPage}, {path: admin123/login, Component: AdminLogin}, {path: *, Component: NotFound}, ], }, ], routerBasename ? {basename: routerBasename} : {} );这个文件是整个项目的路由配置中心相当于我们Java中的Controller层视图解析器的组合负责映射URL和页面组件我们分两部分讲解1. 全局路径前缀basenameconst routerBasename getRouterBasename(); routerBasename ? {basename: routerBasename} : {}这两段配置了前端的baseurl就像在Springboot项目中的xml文件里配置了server.servlet.context-path/{routerBasename}所有对前端的访问都会在域名后加上routerBasename之后才是路由访问路径对应 {index: true, Component: Home},对应 {path: about, Component: About},2. 核心路由配置export const router createBrowserRouter( [ { path: /, Component: Layout, children: [ {index: true, Component: Home}, {path: about, Component: About}, {path: blog, Component: BlogFeedPage}, {path: lab, Component: Lab}, {path: category/:id, Component: CategoryPage}, {path: post/:id, Component: PostPage}, {path: admin123/login, Component: AdminLogin}, {path: *, Component: NotFound}, ], }, ]这一部分是项目的路由可理解为后端的Controller层视图解析器的组合——和Controller一样负责URL映射只不过后端Controller返回数据或通过视图解析器返回页面而前端路由直接返回对应的页面组件。如下Controller RequestMapping(/) // 对应 path: / public class PageController { // 首页 对应 index: true GetMapping() public String home() { return Home;} // /about GetMapping(/about) public String about() {return About;} // /blog GetMapping(/blog) public String blog() {return BlogFeedPage;} // /lab GetMapping(/lab) public String lab() {return Lab;} // /category/123 GetMapping(/category/{id}) public String category(PathVariable Long id) {return CategoryPage;} // /post/456 GetMapping(/post/{id}) public String post(PathVariable Long id) {return PostPage;} // 后台登录 GetMapping(/admin123/login) public String adminLogin() {return AdminLogin;} // 404 对应 path: * GetMapping(/*) public String notFound() {return NotFound;} }今天就review到这里这是我的博客网站https://refract.top/refract-blog/