当前位置:   article > 正文

React简单项目,熟悉项目大致完整流程_react项目

react项目

准备:基本的前端环境,nodejs等 ,编辑器采用vscode、技术采用react、状态管理用mobx、路由react-router-dom

创建
  1. 生成项目: npx create-react-app project_demo
  2. 进入项目目录:cd project_demo
  3. 启动项目: yarn start
调整目录
  1. /public
  2. /src
  3. /asserts //静态资源文件
  4. /components //通用组件
  5. /hooks //封装的钩子函数
  6. /pages //页面
  7. /store //mobx状态仓库
  8. /styles //样式文件
  9. /utils //工具类文件夹:token、anxios、Info等
  10. app.js //根组件
  11. index.js //项目入口
  12. index.css //全局样式
核心代码保留

src/index.js文件

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. import App from './App'
  4. ReactDOM.render(
  5. <React.StrictMode>
  6. <App />
  7. </React.StrictMode>,
  8. document.getElementById('root')
  9. )

src/App.js

  1. export default function App() {
  2. return <div>根组件</div>
  3. }
使用scss预处理器
  1. //安装sass
  2. yarn add sass -D    //=>D表示只在dev环境下生效

创建全局样式文件index.scss

  1. body{
  2.     margin:0;
  3. }
  4. #root{
  5.     height:100%
  6. }
创建几个相关页面:例:登录、布局

pages/Login/index.js

  1. const Login = () => {
  2. return <div>login</div>
  3. }
  4. export default Login

pages/Layout/index.js

  1. const Layout = () => {
  2. return <div>layout</div>
  3. }
  4. export default Layout
创建基础路由
  1. //安装路由
  2. yarn add react-router-dom
  3. //配置基础路由,app.js文件
  4. // 导入路由
  5. import { BrowserRouter, Route, Routes } from 'react-router-dom'
  6. // 导入页面组件
  7. import Login from './pages/Login'
  8. import Layout from './pages/Layout'
  9. // 配置路由规则
  10. function App() {
  11. return (
  12. <BrowserRouter>    //浏览器路由最外层包裹
  13. <div className="App">
  14. <Routes>        //路由外层
  15. <Route path="/" element={<Layout/>}/>    //path:路由地址,element:路由地址对应的页面   
  16. <Route path="/login" element={<Login/>}/>
  17. </Routes>
  18. </div>
  19. </BrowserRouter>
  20. )
  21. }
  22. export default App
使用antd组件库
  1. //安装
  2. yarn add antd
  3. //src/index.js中引入 *=>    新版本中,似乎可以不用在此处引入也同样可以使用,如需引入则是按照如下
  4. import 'antd/dist/antd.mis.css
  5. import './index.css'
  6. //然后直接再页面中,再引入想要使用的组件即可。     例:
  7. import { Button } from 'antd'
配置别名路径(通过第三方库Craco)

作用:可以通过配置@来简化路径

  1. //安装
  2. yarn add -D @craco/craco
  3. //项目根目录创建:craco.config.js,并配置路径别名
  4. const path = require('path')
  5. module.exports = {
  6. // webpack 配置
  7. webpack: {
  8. // 配置别名
  9. alias: {
  10. // 约定:使用 @ 表示 src 文件所在路径
  11. '@': path.resolve(__dirname, 'src')
  12. }
  13. }
  14. }
  15. //修改package.json脚本命令
  16. // 将 start/build/test 三个命令修改为 craco 方式
  17. "scripts": {
  18. "start": "craco start",
  19. "build": "craco build",
  20. "test": "craco test",
  21. "eject": "react-scripts eject"
  22. }
  23. //此时,vscode在输入@的时候还不会显示提示,所以此时需要船舰jsconfig.json,并添加如下配置
  24. {
  25. "compilerOptions": {
  26. "baseUrl": "./",
  27. "paths": {
  28. "@/*": ["src/*"]        //=>告诉编辑器@在路径中的意思
  29. }
  30. }
  31. }

...//省略页面编写代码

封装anxios

utils/request.js

  1. import axios from 'axios'
  2. const request = axios.create({
  3. baseURL: ' ',    //服务地址
  4. timeout: 5000
  5. })
  6. // 添加请求拦截器
  7. request.interceptors.request.use((config)=> {
  8. return config
  9. }, (error)=> {
  10. return Promise.reject(error)
  11. })
  12. // 添加响应拦截器
  13. request.interceptors.response.use((response)=> {
  14. // 2xx 范围内的状态码都会触发该函数。
  15. // 对响应数据做点什么
  16. return response
  17. }, (error)=> {
  18. // 超出 2xx 范围的状态码都会触发该函数。
  19. // 对响应错误做点什么
  20. return Promise.reject(error)
  21. })
  22. export { request }
通过utils中统一管理

utils/index.js

  1. import {request} from './request';
  2. export { request }
配置登录mobx(LoginStore)

/store/login.Store.js

  1. import { removeToken, request, setToken } from "@/utils"
  2. import { makeAutoObservable } from "mobx"
  3. class LoginStore {
  4. token = this.getToken || ''
  5. constructor() {
  6. makeAutoObservable(this)
  7. }
  8. //getToken
  9. login = async ({ mobile, code }) => {
  10. //调用登录接口、存入token
  11. const res = await request.post('/api', {
  12. mobile, code
  13. })
  14. console.log(res)
  15. this.token = res.data
  16. setToken(this.token)
  17. }
  18. loginOut = () => {
  19. removeToken()
  20. }
  21. }
  22. export default LoginStore
统一管理

创建store/index.js文件

  1. import React from "react"
  2. import LoginStore from './login.Store'
  3. class RootStore {
  4. // 组合模块
  5. constructor() {
  6. this.loginStore = new LoginStore()
  7. }
  8. }
  9. // 导入useStore方法供组件使用数据
  10. const StoresContext = React.createContext(new RootStore())
  11. export const useStore = () => React.useContext(StoresContext)
使token持久化

封装utils/token.js

  1. const TOKEN_KEY = 'geek_pc'
  2. const getToken = () => localStorage.getItem(TOKEN_KEY)
  3. const setToken = token => localStorage.setItem(TOKEN_KEY, token)
  4. const clearToken = () => localStorage.removeItem(TOKEN_KEY)
  5. export { getToken, setToken, clearToken }

在调用登录接口的同时,将token设置为接口返回的token数据调用token.js里的setToken

请求拦截器注入token *

将token通过请求拦截器注入到token请求头中

  1. utils/request.js    => axios(此处注入token) =>    .....
  2. //通过config.headers.Authorization = Bearer ${token} 拼接上去
  3. //utils/request.js
  4. http.interceptors.request.use(config => {
  5. // if not login add token
  6. const token = getToken()
  7. if (token) {
  8. config.headers.Authorization = `Bearer ${token}`
  9. }
  10. return config
  11. })
路由鉴权

实现非登录用户过滤拦截并跳转到登录页面

封装组件components/AuthRoute/index.js

  1. // 1. 判断token是否存在
  2. // 2. 如果存在 直接正常渲染
  3. // 3. 如果不存在 重定向到登录路由
  4. // 高阶组件:把一个组件当成另外一个组件的参数传入 然后通过一定的判断 返回新的组件
  5. import { getToken } from '@/utils'
  6. import { Navigate } from 'react-router-dom'
  7. function AuthRoute ({ children }) {
  8. const isToken = getToken()
  9. if (isToken) {
  10. return <>{children}</>
  11. } else {
  12. return <Navigate to="/login" replace />
  13. }
  14. }
  15. // <AuthComponent> <Layout/> </AuthComponent>
  16. // 登录:<><Layout/></>
  17. // 非登录:<Navigate to="/login" replace />
  18. export { AuthRoute }

src/App.js

  1. import { Router, Route } from 'react-router-dom'
  2. import { AuthRoute } from '@/components/AuthRoute'
  3. import Layout from '@/pages/Layout'
  4. import Login from '@/pages/Login'
  5. function App() {
  6. return (
  7. <Router>
  8. <Routes>
  9. {/* 需要鉴权的路由 */}
  10. <Route path="/*" element={
  11. <AuthRoute>
  12. <Layout />
  13. </AuthRoute>
  14. } />
  15. {/* 不需要鉴权的路由 */}
  16. <Route path='/login' element={<Login />} />
  17. </Routes>
  18. </Router>
  19. )
  20. }
  21. export default App

退出登录后,需要清除token

...

项目打包
  1. 1、yarn build     =>打包生产的内容会放在根下的build文件夹中
  2. 2、npm i -g serve    =>提供serve命令,启动打包后的本地服务
  3.   serve -s ./build    =>在build目录中启动
  4. 3http://localhost:3000
打包体积分析
  1. 1、yarn add source-map-explorer    =>安装分析打包体积的包
  2. 2、在package.json文件的scripts标签中添加
  3.         "scripts": {
  4.         "analyze": "source-map-explorer 'build/static/js/*.js'",
  5.         }
  6. 3、项目打包:yarn build
  7. 4、运行分析命令:yarn analyze即可在浏览器中看到包大小
优化配置CDN

通过craco修改webpack配置,实现CDN优化

craco.config.js

  1. // 添加自定义对于webpack的配置
  2. const path = require('path')
  3. const { whenProd, getPlugin, pluginByName } = require('@craco/craco')
  4. module.exports = {
  5. // webpack 配置
  6. webpack: {
  7. // 配置别名
  8. alias: {
  9. // 约定:使用 @ 表示 src 文件所在路径
  10. '@': path.resolve(__dirname, 'src')
  11. },
  12. // 配置webpack
  13. // 配置CDN
  14. configure: (webpackConfig) => {
  15. // webpackConfig自动注入的webpack配置对象
  16. // 可以在这个函数中对它进行详细的自定义配置
  17. // 只要最后return出去就行
  18. let cdn = {
  19. js: [],
  20. css: []
  21. }
  22. // 只有生产环境才配置
  23. whenProd(() => {
  24. // key:需要不参与打包的具体的包
  25. // value: cdn文件中 挂载于全局的变量名称 为了替换之前在开发环境下
  26. // 通过import 导入的 react / react-dom
  27. webpackConfig.externals = {
  28. react: 'React',
  29. 'react-dom': 'ReactDOM'
  30. }
  31. // 配置现成的cdn 资源数组 现在是公共为了测试
  32. // 实际开发的时候 用公司自己花钱买的cdn服务器
  33. cdn = {
  34. js: [
  35. 'https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js',
  36. 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js',
  37. ],
  38. css: []
  39. }
  40. })
  41. // 都是为了将来配置 htmlWebpackPlugin插件 将来在public/index.html注入
  42. // cdn资源数组时 准备好的一些现成的资源
  43. const { isFound, match } = getPlugin(
  44. webpackConfig,
  45. pluginByName('HtmlWebpackPlugin')
  46. )
  47. if (isFound) {
  48. // 找到了HtmlWebpackPlugin的插件
  49. match.userOptions.cdn = cdn
  50. }
  51. return webpackConfig
  52. }
  53. }
  54. }

同时需要在public/index.html中加入如下代码

  1. <body>
  2. <div id="root"></div>
  3. <!-- 加载第三发包的 CDN 链接 -->
  4. <% htmlWebpackPlugin.userOptions.cdn.js.forEach(cdnURL => { %>
  5. <script src="<%= cdnURL %>"></script>
  6. <% }) %>
  7. </body>
路由懒加载(按需加载)

App导入Suspense组件 => Router内部使用Suspense包裹Routes组件 => 为Suspense提供fallback属性,指定loading => 导入laze函数,改为懒加载方式导入路由

app.js

  1. import { Routes, Route } from 'react-router-dom'
  2. import { HistoryRouter, history } from './utils/history'
  3. import { AuthRoute } from './components/AuthRoute'
  4. // 导入必要组件
  5. import { lazy, Suspense } from 'react'
  6. // 按需导入路由组件
  7. const Login = lazy(() => import('./pages/Login'))
  8. const Layout = lazy(() => import('./pages/Layout'))
  9. const Home = lazy(() => import('./pages/Home'))
  10. const Article = lazy(() => import('./pages/Article'))
  11. const Publish = lazy(() => import('./pages/Publish'))
  12. function App () {
  13. return (
  14. <HistoryRouter history={history}>
  15. <Suspense
  16. fallback={
  17. <div
  18. style={{
  19. textAlign: 'center',
  20. marginTop: 200
  21. }}
  22. >
  23. loading...
  24. </div>
  25. }
  26. >
  27. <Routes>
  28. {/* 需要鉴权的路由 */}
  29. <Route path="/" element={
  30. <AuthRoute>
  31. <Layout />
  32. </AuthRoute>
  33. }>
  34. {/* 二级路由默认页面 */}
  35. <Route index element={<Home />} />
  36. <Route path="article" element={<Article />} />
  37. <Route path="publish" element={<Publish />} />
  38. </Route>
  39. {/* 不需要鉴权的路由 */}
  40. <Route path='/login' element={<Login />} />
  41. </Routes>
  42. </Suspense>
  43. </HistoryRouter>
  44. )
  45. }
  46. export default App
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/671196
推荐阅读
相关标签
  

闽ICP备14008679号