React项目 新闻发布系统 项目初始化与路由搭建
经过一段时间系统的学习完React,也是轮到咱第一次系统的来编写一个完整的前端项目。项目主要内容是制作一个React开发的新闻发布系统。这个系列呢主要还是对项目搭建步骤的系统性总结,和对项目制作过程中一些问题的记录。
本章主要讲述 1.项目的搭建 2.项目路由搭建
一 :项目搭建
(1)项目初始化
和老师的教程不一样 kerwin老师使用的webpack提供的CRA来快速搭建一个React,由于CRA搭建项目对于我的网络环境来说特别慢,所以我在这里使用的是vite来搭建。
npm create vite@latest
然后项目选择使用React框架 语言使用JavaScript 在初始化创建完项目目录之后 继续执行命令
npm install
等待命令执行完之后 我们就可以打开任务了 执行命令
npm run dev
至此对项目的初始化完成
(2)项目目录结构搭建
先来看目录结构
主要更改的结构是src目录中的结构 其中component用来存放一些可以复用的组件 router用来存放路由信息 view就是主要视图了 app.jsx就是项目的根目录了 其中最下面还有一个vite.config文件他的作用后面细讲。
再看看view里面的组件
这就是项目的基础结构了
(3)跨域请求问题以及解决方法
跨域问题 也叫跨域资源共享问题 因为浏览器设置了同源策略 就是只能访问同源资源 如果后端服务器的端口号 域名等出现细微变化就会导致无法访问后端资源的问题 后端的解决方法是说用cors中间件来解决,而对于前端来说需要单独配置一个文件来解决卡与文件。不同于CRA创建的React项目 使用vite创建的React解决跨域问题 需要在根目录创建一个vite.config.js文件 通过反向代理解决。
下面的代码中 proxy就是配置反向代理的配置区域。‘/ajax’等表示代理所有以‘/ajax’开头的请求 下面的traget表示需要代理的服务器地址 下面的changeOrigin是固定写法。如果有其他需要跨域请求的地址可以在这里配置
export default defineConfig({plugins: [react()],server: {proxy: {// 代理所有以 /api 开头的请求'/ajax': {target: 'http://localhost:3000', // 需要请求的后端服务器地址changeOrigin: true,// rewrite: (path) => path.replace(/^\/api/, '') // 可选:重写路径},// 可以配置多个代理规则'/api': {target: 'http://localhost:3000',changeOrigin: true},'/yet-another-api': {target: 'http://localhost:5173',changeOrigin: true}}}
})
(4)部分插件下载
我们还需要下载一些插件 首先是antd 组件库 axios请求接口 react-router-dom路由 json-server模拟后端接口 sass 等等
二:项目路由搭建
(1)路由实例页面
在项目路由搭建的时候 kerwin老师用的是react-router-dom v5版本的老方法,对于react19来说已经不适用了 所以我这里使用react-router-dom v6的最新写法来搭建项目路由
在router文件夹中创建index.js存放路由的实例 在本项目中使用的是hash路由 使用createHashRouter创建路由实例
const router = createHashRouter([])
然后根据项目要求编写路由
//由于kerwin写路由的方法是使用的react-router-dom v5 所以我们使用react-router-dom v6的写法 使用router组件和RouterProvider组件来挂载路由import { createHashRouter } from "react-router-dom";
import Login from "../view/Login";
import NewSandBox from '../view/NewSandBox'
import PrivateRouter from "../components/PrivateRouter";
import Home from "../view/Home/Home";
import UserList from "../view/NewSandBox/User-manage/UserList";
import RoleList from "../view/NewSandBox/Role-manage/RoleList";
import RightList from "../view/NewSandBox/Right-manage/RightList";
import Draft from "../view/NewSandBox/news-manage/Draft";
import Category from "../view/NewSandBox/news-manage/Category";
import NotFund from "../view/404/404";
import { Navigate } from "react-router-dom";
import UserAdd from "../view/NewSandBox/User-manage/UserAdd";
import UserUpdate from "../view/NewSandBox/User-manage/UserUpdate"
import UserDelete from "../view/NewSandBox/User-manage/UserDelete";
import RoleDelete from "../view/NewSandBox/Role-manage/RoleDelete";
import RoleUpdate from "../view/NewSandBox/Role-manage/RoleUpdate";
import RightUpdate from "../view/NewSandBox/Right-manage/RightUpdate";
import RightDelete from "../view/NewSandBox/Right-manage/RightDelete";
import Published from "../view/NewSandBox/publish-manage/Published";
import Unpublished from "../view/NewSandBox/publish-manage/Unpublished";
import Sunset from "../view/NewSandBox/publish-manage/Sunset";
import NewsAdd from "../view/NewSandBox/news-manage/NewsAdd";
import NewsList from "../view/NewSandBox/news-manage/NewsList";
import NewsPreview from "../view/NewSandBox/news-manage/NewsPreview";
import NewsUpdate from "../view/NewSandBox/news-manage/NewsUpdate";
import Audit from "../view/NewSandBox/audit-manage/Audit";
import AuditList from "../view/NewSandBox/audit-manage/AuditList";
//使用createHashRouter创建路由
const router = createHashRouter([{path: '/login',element: <Login/>},{path: '/',element:(<PrivateRouter><NewSandBox/></PrivateRouter>), //如果未授权 就会重定向到login页面 需要使用路由守卫 PrivateRouter 来包裹NewSandBox组件 ,children:[{//home组件path:'home',element:<Home/>},{//用户列表组件path:'user-manage/list',element:<UserList/>},{//角色列表组件path:'right-manage/role/list',element:<RoleList/>},{//权限列表组件path:'right-manage/right/list',element:<RightList/>},{path:'/404',element:<NotFund/>},{path:'/user-manage/add',element:<UserAdd/> //*},{path:'/user-manage/delete',element:<UserDelete/> //*},{path:'/user-manage/update',element:<UserUpdate/>},{path:'/right-manage/role/update',element:<RoleUpdate/> //*},{path:'/right-manage/role/delete',element:<RoleDelete/> //*},{path:'/right-manage/right/update',element:<RightUpdate/> //*},{path:'/right-manage/right/delete',element:<RightDelete/> //*},{path:'/news-manage/list',element:<NewsList/> //*},{path:'/news-manage/add',element:<NewsAdd/> //*},{path:'/news-manage/preview/:id',element:<NewsPreview/> //*},{path:'/news-manage/update/:id',element:<NewsUpdate/> //*},{path:'/news-manage/draft',element:<Draft/>},{path:'/news-manage/category',element:<Category/>},{path:'/audit-manage/audit',element:<Audit/>},{path:'/audit-manage/list',element:<AuditList/>},{path:'/publish-manage/unpublished',element:<Unpublished/>},{path:'/publish-manage/published',element:<Published/>},{path:'/publish-manage/sunset',element:<Sunset/>}, //重定向{path:'/',element:<Navigate to='/home'/>},{path:'*',element:<Navigate to='/404'/>}]}
])export default router;
主要的路由有两个 一个是登录页面的路由'/login’ 一个是初始页面的路由‘/’ 其余的都是从属于初始页面底下的子路由 包含在children数组里面。最后我们导出路由实例。值得注意的是 我们在初始页面的主路由中创建了一个路由守卫 用来验证用户是否登录成功。不细说 后续会讲
路由里面的重定向就是当我们访问路径如果不存在 或是只有'/’的时候会跳转到404页面和home页面,在创建路由之前记得把该创建的页面都提前创建好。
(2)挂载路由实例
后面 我们在app.jsx中挂载 创建的路由实例 在挂载之前需要导入RouterProvide组件 这是react-router-dom的内置组件 还需要引入我们刚刚创建的router实例,后面进行挂载即可
import { Button } from "antd"
import "./app.scss"
import router from "./router/index"
import { RouterProvider } from "react-router-dom"
function App(){return(<><RouterProvider router={router}/></>)
}export default App
(3)路由守卫
先介绍一下路由守卫 路由守卫是一个用来保护子组件的组件 在这个项目中该路由守卫的职责就是获取初始页面组件 然后通过验证用户是否拿到token成功登录 如果没有就跳转到登录页面。因为项目暂时没有后端传入数据 所以暂时使用本地存储里面存好的token作为登录验证的token
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";//路由守卫 需要传入一个子组件 表示路由守卫保护的组件
const PrivateRouter=({children})=>{const navigate=useNavigate();useEffect(()=>{//从后端拿到user数据const userToken = localStorage.getItem('token');if(!userToken){//replace: true 是React Router v6中 navigate() 函数的一个配置参数,用于控制路由跳转的行为。它的主要作用是: 用新的路由替换浏览器历史记录中的当前条目,而不是在历史记录中添加新条目 。navigate('/login',{replace:true});}},[navigate])// 同步检查token,存在则渲染子组件,不存在则不渲染任何内容const userToken = localStorage.getItem('token');return userToken ? children : null;
}
export default PrivateRouter;
在上面的组件和路由都创建完之后我们就可以开始着手开发页面了