赞
踩
准备:基本的前端环境,nodejs等 ,编辑器采用vscode、技术采用react、状态管理用mobx、路由react-router-dom
- 生成项目: npx create-react-app project_demo
- 进入项目目录:cd project_demo
- 启动项目: yarn start
- /public
- /src
- /asserts //静态资源文件
- /components //通用组件
- /hooks //封装的钩子函数
- /pages //页面
- /store //mobx状态仓库
- /styles //样式文件
- /utils //工具类文件夹:token、anxios、Info等
- app.js //根组件
- index.js //项目入口
- index.css //全局样式
src/index.js文件
- import React from 'react'
- import ReactDOM from 'react-dom'
- import App from './App'
-
- ReactDOM.render(
- <React.StrictMode>
- <App />
- </React.StrictMode>,
- document.getElementById('root')
- )
src/App.js
- export default function App() {
- return <div>根组件</div>
- }
- //安装sass
- yarn add sass -D //=>D表示只在dev环境下生效
创建全局样式文件index.scss
- body{
- margin:0;
- }
- #root{
- height:100%
- }
pages/Login/index.js
- const Login = () => {
- return <div>login</div>
- }
- export default Login
pages/Layout/index.js
- const Layout = () => {
- return <div>layout</div>
- }
- export default Layout
- //安装路由
- yarn add react-router-dom
- //配置基础路由,app.js文件
- // 导入路由
- import { BrowserRouter, Route, Routes } from 'react-router-dom'
-
- // 导入页面组件
- import Login from './pages/Login'
- import Layout from './pages/Layout'
-
- // 配置路由规则
- function App() {
- return (
- <BrowserRouter> //浏览器路由最外层包裹
- <div className="App">
- <Routes> //路由外层
- <Route path="/" element={<Layout/>}/> //path:路由地址,element:路由地址对应的页面
- <Route path="/login" element={<Login/>}/>
- </Routes>
- </div>
- </BrowserRouter>
- )
- }
-
- export default App
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- //安装
- yarn add antd
- //src/index.js中引入 *=> 新版本中,似乎可以不用在此处引入也同样可以使用,如需引入则是按照如下
- import 'antd/dist/antd.mis.css
- import './index.css'
- //然后直接再页面中,再引入想要使用的组件即可。 例:
- import { Button } from 'antd'
作用:可以通过配置@来简化路径
- //安装
- yarn add -D @craco/craco
- //项目根目录创建:craco.config.js,并配置路径别名
- const path = require('path')
-
- module.exports = {
- // webpack 配置
- webpack: {
- // 配置别名
- alias: {
- // 约定:使用 @ 表示 src 文件所在路径
- '@': path.resolve(__dirname, 'src')
- }
- }
- }
-
- //修改package.json脚本命令
- // 将 start/build/test 三个命令修改为 craco 方式
- "scripts": {
- "start": "craco start",
- "build": "craco build",
- "test": "craco test",
- "eject": "react-scripts eject"
- }
-
- //此时,vscode在输入@的时候还不会显示提示,所以此时需要船舰jsconfig.json,并添加如下配置
- {
- "compilerOptions": {
- "baseUrl": "./",
- "paths": {
- "@/*": ["src/*"] //=>告诉编辑器@在路径中的意思
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
...//省略页面编写代码
utils/request.js
- import axios from 'axios'
-
- const request = axios.create({
- baseURL: ' ', //服务地址
- timeout: 5000
- })
- // 添加请求拦截器
- request.interceptors.request.use((config)=> {
- return config
- }, (error)=> {
- return Promise.reject(error)
- })
-
- // 添加响应拦截器
- request.interceptors.response.use((response)=> {
- // 2xx 范围内的状态码都会触发该函数。
- // 对响应数据做点什么
- return response
- }, (error)=> {
- // 超出 2xx 范围的状态码都会触发该函数。
- // 对响应错误做点什么
- return Promise.reject(error)
- })
-
- export { request }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
utils/index.js
- import {request} from './request';
- export { request }
/store/login.Store.js
- import { removeToken, request, setToken } from "@/utils"
- import { makeAutoObservable } from "mobx"
-
-
- class LoginStore {
- token = this.getToken || ''
- constructor() {
- makeAutoObservable(this)
- }
-
- //getToken
- login = async ({ mobile, code }) => {
- //调用登录接口、存入token
- const res = await request.post('/api', {
- mobile, code
- })
- console.log(res)
- this.token = res.data
- setToken(this.token)
- }
-
- loginOut = () => {
- removeToken()
- }
- }
-
- export default LoginStore
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
创建store/index.js文件
- import React from "react"
- import LoginStore from './login.Store'
-
- class RootStore {
- // 组合模块
- constructor() {
- this.loginStore = new LoginStore()
- }
- }
- // 导入useStore方法供组件使用数据
- const StoresContext = React.createContext(new RootStore())
- export const useStore = () => React.useContext(StoresContext)
封装utils/token.js
- const TOKEN_KEY = 'geek_pc'
-
- const getToken = () => localStorage.getItem(TOKEN_KEY)
- const setToken = token => localStorage.setItem(TOKEN_KEY, token)
- const clearToken = () => localStorage.removeItem(TOKEN_KEY)
-
- export { getToken, setToken, clearToken }
在调用登录接口的同时,将token设置为接口返回的token数据调用token.js里的setToken
将token通过请求拦截器注入到token请求头中
- utils/request.js => axios(此处注入token) => .....
-
- //通过config.headers.Authorization = Bearer ${token} 拼接上去
-
- //utils/request.js
- http.interceptors.request.use(config => {
- // if not login add token
- const token = getToken()
- if (token) {
- config.headers.Authorization = `Bearer ${token}`
- }
- return config
- })
实现非登录用户过滤拦截并跳转到登录页面
封装组件components/AuthRoute/index.js
- // 1. 判断token是否存在
- // 2. 如果存在 直接正常渲染
- // 3. 如果不存在 重定向到登录路由
-
- // 高阶组件:把一个组件当成另外一个组件的参数传入 然后通过一定的判断 返回新的组件
- import { getToken } from '@/utils'
- import { Navigate } from 'react-router-dom'
-
- function AuthRoute ({ children }) {
- const isToken = getToken()
- if (isToken) {
- return <>{children}</>
- } else {
- return <Navigate to="/login" replace />
- }
- }
-
- // <AuthComponent> <Layout/> </AuthComponent>
- // 登录:<><Layout/></>
- // 非登录:<Navigate to="/login" replace />
-
- export { AuthRoute }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
src/App.js
- import { Router, Route } from 'react-router-dom'
- import { AuthRoute } from '@/components/AuthRoute'
- import Layout from '@/pages/Layout'
- import Login from '@/pages/Login'
-
- function App() {
- return (
- <Router>
- <Routes>
- {/* 需要鉴权的路由 */}
- <Route path="/*" element={
- <AuthRoute>
- <Layout />
- </AuthRoute>
- } />
- {/* 不需要鉴权的路由 */}
- <Route path='/login' element={<Login />} />
- </Routes>
- </Router>
- )
- }
- export default App
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
退出登录后,需要清除token
...
- 1、yarn build =>打包生产的内容会放在根下的build文件夹中
- 2、npm i -g serve =>提供serve命令,启动打包后的本地服务
- serve -s ./build =>在build目录中启动
- 3、http://localhost:3000
- 1、yarn add source-map-explorer =>安装分析打包体积的包
- 2、在package.json文件的scripts标签中添加
- "scripts": {
- "analyze": "source-map-explorer 'build/static/js/*.js'",
- }
- 3、项目打包:yarn build
- 4、运行分析命令:yarn analyze即可在浏览器中看到包大小
通过craco修改webpack配置,实现CDN优化
craco.config.js
- // 添加自定义对于webpack的配置
-
- const path = require('path')
- const { whenProd, getPlugin, pluginByName } = require('@craco/craco')
-
- module.exports = {
- // webpack 配置
- webpack: {
- // 配置别名
- alias: {
- // 约定:使用 @ 表示 src 文件所在路径
- '@': path.resolve(__dirname, 'src')
- },
- // 配置webpack
- // 配置CDN
- configure: (webpackConfig) => {
- // webpackConfig自动注入的webpack配置对象
- // 可以在这个函数中对它进行详细的自定义配置
- // 只要最后return出去就行
- let cdn = {
- js: [],
- css: []
- }
- // 只有生产环境才配置
- whenProd(() => {
- // key:需要不参与打包的具体的包
- // value: cdn文件中 挂载于全局的变量名称 为了替换之前在开发环境下
- // 通过import 导入的 react / react-dom
- webpackConfig.externals = {
- react: 'React',
- 'react-dom': 'ReactDOM'
- }
- // 配置现成的cdn 资源数组 现在是公共为了测试
- // 实际开发的时候 用公司自己花钱买的cdn服务器
- cdn = {
- js: [
- 'https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js',
- 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js',
- ],
- css: []
- }
- })
-
- // 都是为了将来配置 htmlWebpackPlugin插件 将来在public/index.html注入
- // cdn资源数组时 准备好的一些现成的资源
- const { isFound, match } = getPlugin(
- webpackConfig,
- pluginByName('HtmlWebpackPlugin')
- )
-
- if (isFound) {
- // 找到了HtmlWebpackPlugin的插件
- match.userOptions.cdn = cdn
- }
-
- return webpackConfig
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
同时需要在public/index.html中加入如下代码
- <body>
- <div id="root"></div>
- <!-- 加载第三发包的 CDN 链接 -->
- <% htmlWebpackPlugin.userOptions.cdn.js.forEach(cdnURL => { %>
- <script src="<%= cdnURL %>"></script>
- <% }) %>
- </body>
App导入Suspense组件 => Router内部使用Suspense包裹Routes组件 => 为Suspense提供fallback属性,指定loading => 导入laze函数,改为懒加载方式导入路由
app.js
- import { Routes, Route } from 'react-router-dom'
- import { HistoryRouter, history } from './utils/history'
- import { AuthRoute } from './components/AuthRoute'
-
- // 导入必要组件
- import { lazy, Suspense } from 'react'
- // 按需导入路由组件
- const Login = lazy(() => import('./pages/Login'))
- const Layout = lazy(() => import('./pages/Layout'))
- const Home = lazy(() => import('./pages/Home'))
- const Article = lazy(() => import('./pages/Article'))
- const Publish = lazy(() => import('./pages/Publish'))
-
- function App () {
- return (
- <HistoryRouter history={history}>
- <Suspense
- fallback={
- <div
- style={{
- textAlign: 'center',
- marginTop: 200
- }}
- >
- loading...
- </div>
- }
- >
- <Routes>
- {/* 需要鉴权的路由 */}
- <Route path="/" element={
- <AuthRoute>
- <Layout />
- </AuthRoute>
- }>
- {/* 二级路由默认页面 */}
- <Route index element={<Home />} />
- <Route path="article" element={<Article />} />
- <Route path="publish" element={<Publish />} />
- </Route>
- {/* 不需要鉴权的路由 */}
- <Route path='/login' element={<Login />} />
- </Routes>
- </Suspense>
- </HistoryRouter>
- )
- }
-
- export default App
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。