当前位置:   article > 正文

【React】从0到1搭建你的React18项目

react18项目

在这里插入图片描述

一,项目搭建


安装脚手架CRA

  1. 使用create-react-app生成项目 npx create-react-app 自定义项目名

  2. 进入根目录 cd 自定义项目名

  3. 启动项目 npm run start

  4. 调整项目目录结构

    /src
      /assets         项目资源文件,比如,图片 等
      /components     通用组件
      /pages          页面
      /store          mobx 状态仓库
      /utils          工具,比如,token、axios 的封装等
      App.js          根组件
      index.css       全局样式
      index.js        项目入口
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

保留核心代码

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')
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

src/App.js

export default function App() {
  return <div>根组件</div>
}
  • 1
  • 2
  • 3

二、使用gitee管理项目


  1. 在项目根目录打开终端,并初始化 git 仓库(如果已经有了 git 仓库,无需重复该步),命令:git init
  2. 添加项目内容到暂存区:git add .
  3. 提交项目内容到仓库区:git commit -m '项目初始化'
  4. 添加 remote 仓库地址:git remote add origin [gitee 仓库地址]
  5. 将项目内容推送到 gitee:git push origin master -u

三、使用scss预处理器


SASS 是一种预编译的 CSS,作用类似于 Less。由于 React 中内置了处理 SASS 的配置,所以,在 CRA 创建的项目中,可以直接使用 SASS 来写样式。

  1. 安装解析 sass 的包:npm i sass -D

  2. src根目录创建全局样式文件:index.scss

    body {
      margin: 0;
    }
    
    #root {
      height: 100%;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

四、配置路由


基础路由

  1. 安装路由:npm i react-router-dom

  2. pages 目录中创建两个路由测试文件夹:LoginLayout

  3. 分别在创建的两个目录中创建 index.js 文件,并创建一个简单的组件后导出:
    pages/Login/index.js

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

    pages/Layout/index.js

    const Layout = () => {
      return <div>layout</div>
    }
    export default Layout
    
    • 1
    • 2
    • 3
    • 4
  4. App 组件中,导入路由组件以及两个页面组件

  5. 配置 LoginLayout 的路由规则

    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/>}>
               		{/* 配置嵌套路由*/}
    				{/* 二级路由默认页面 */}
    			    {/*<Route index element={<组件1/>} /> */}
    			    {/*<Route path="article" element={<Article />} /> */}
    			</Route>
                <Route path="/login" element={<Login/>}/>
            </Routes>
          </div>
        </BrowserRouter>
      )
    }
    
    export default App
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

在非组件环境下拿到路由信息

  1. 安装:npm i history

  2. 创建 utils/history.js 文件

    utils/history.js

    // https://github.com/remix-run/react-router/issues/8264
    
    import { createBrowserHistory } from 'history'
    import { unstable_HistoryRouter as HistoryRouter } from 'react-router-dom'
    const history = createBrowserHistory()
    
    export {
      HistoryRouter,
      history
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  3. 在app.js中使用我们新建的路由并配置history参数

    app.js

    import { HistoryRouter, history } from './utils/history'
    
    function App() {
      return (
      	//HistoryRouter替换BrowserRouter
        <HistoryRouter history={history}>
           ...省略无关代码
        </HistoryRouter>
      )
    }
    
    export default App
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  4. 使用案例

    utils/http.js

    import { history } from './history'
    
    http.interceptors.response.use(
      response => {
        return response.data
      },
      error => {
        if (error.response.status === 401) {
          // 跳转到登录页
          history.push('/login')
        }
        return Promise.reject(error)
      }
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

路由懒加载

  1. App 组件中,导入 Suspense 组件
  2. 在 路由Router 内部,使用 Suspense 组件包裹组件内容
  3. Suspense 组件提供 fallback 属性,指定 loading 占位内容
  4. 导入 lazy 函数,并修改为懒加载方式导入路由组件

App.js

import { Routes, Route } from 'react-router-dom'
import { HistoryRouter, history } from './utils/history'


// 导入必要组件
import { lazy, Suspense } from 'react'
// 按需导入路由组件
const Login = lazy(() => import('./pages/Login'))
const Layout = lazy(() => import('./pages/Layout'))
function App () {
  return (
    <HistoryRouter history={history}>
      <Suspense
        fallback={
          <div
            style={{
              textAlign: 'center',
              marginTop: 200
            }}
          >
            loading...
          </div>
        }
      >
		 <Routes>
            <Route path="/" element={<Layout/>}>
           		{/* 配置嵌套路由*/}
				{/* 二级路由默认页面 */}
			    {/*<Route index element={<组件1/>} /> */}
			    {/*<Route path="article" element={<Article />} /> */}
			</Route>
            <Route path="/login" element={<Login/>}/>
        </Routes>
      </Suspense>
    </HistoryRouter>
  )
}

export default App
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

五、组件库antd使用


  1. 安装 antd 组件库:npm i antd

  2. 全局导入 antd 组件库的样式
    src/index.js:

    // 先导入 antd 样式文件
    // https://github.com/ant-design/ant-design/issues/33327
    import 'antd/dist/antd.min.css'
    // 再导入全局样式文件,防止样式覆盖!
    import './index.css'
    
    • 1
    • 2
    • 3
    • 4
    • 5
  3. 导入 Button 组件进行测试

  4. Login 页面渲染 Button 组件进行测试
    pages/Login/index.js

    import { Button } from 'antd'
    
    const Login = () => (
      <div>
        <Button type="primary">Button</Button>
      </div>
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

注意

  1. src/index.js文件中导入 antd 的样式文件
  2. antd 的样式文件和我们自己的全局样式文件的导入顺序

六、配置别名路径


安装@craco/craco

自定义 CRA 的默认配置
craco 配置文档

  • CRA 将所有工程化配置,都隐藏在了 react-scripts 包中,所以项目中看不到任何配置信息
  • 如果要修改 CRA 的默认配置,有以下几种方案:
    1. 通过第三方库来修改,比如,@craco/craco推荐
    2. 通过执行 yarn eject 命令,释放 react-scripts 中的所有配置到项目中
  1. 安装修改 CRA 配置的包:npm i -D @craco/craco

  2. 在项目根目录中创建 craco 的配置文件:craco.config.js,并在配置文件中配置路径别名

    craco.config.js

    const path = require('path')
    
    module.exports = {
      // webpack 配置
      webpack: {
        // 配置别名
        alias: {
          // 约定:使用 @ 表示 src 文件所在路径
          '@': path.resolve(__dirname, 'src')
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  3. 修改 package.json 中的脚本命令

    package.json

    // 将 start/build/test 三个命令修改为 craco 方式
    "scripts": {
      "start": "craco start",
      "build": "craco build",
      "test": "craco test",
      "eject": "react-scripts eject"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  4. 在代码中,就可以通过 @ 来表示 src 目录的绝对路径

  5. 重启项目,让配置生效

@别名路径提示

  1. 在项目根目录创建 jsconfig.json 配置文件
  2. 在配置文件中添加以下配置
    {
    
      "compilerOptions": {
        "baseUrl": "./",
        "paths": {
          "@/*": ["src/*"]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

vscode会自动读取jsconfig.json 中的配置,让vscode知道@就是src目录

七、安装dev-tools调试工具


Edge插件下载链接
在这里插入图片描述

八、封装axios工具模块


  1. 安装axios :npm i axios

  2. 创建 utils/http.js 文件

    utils/http.js

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

    utils/index.js

    import { http } from './http'
    export {  http }
    
    • 1
    • 2

九、使用mobx


模块化配置

  1. 安装mobx: npm i mobx mobx-react-lite

  2. store文件夹下创建单一模块store
    例:store/use.Store.js

    //用户模块
    import { computed, makeAutoObservable } from "mobx";
    class UserStore {
      //定义数据
      userinfo= [];
      constructor() {
        //响应式处理
        makeAutoObservable(this, {
          // 标记computed
          fillterList: computed,
        });
        //如果没有计算属性直接:
        //makeAutoObservable(this);
      }
      //get计算属性:computed,计算属性需要在makeAutoObservable里做一下标记
      get fillterList() {
        return this.userinfo.filter((item) => item.name==='ailjx');
      }
      addUse = () => {
        this.userinfo.push({//...});
      };
    }
    
    //导出
    export default UserStore;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  3. store文件下创建index.js统一导出store

    store/index.js

    import React from "react";
    import UserStore from "./use.Store";
    class RootStore {
      // 组合store
      constructor() {
        //对子模块进行实例化操作并赋值给RootStore对应的属性
        //这样将来实例化RootStore的时候就可以通过对应的属性获取导入的对应子模块的实例对象
        this.userStore= new UserStore();
    	//多个模块按照上述语法补充...
      }
    }
    
    //实例化根store注入context
    const rootStore = new RootStore();
    //使用React的useContext机制 导出useStore方法,供业务组件统一使用
    //useContext查找机制:优先从Provider value找,如果找不到,就会找createContext方法传递过来的默认参数
    //核心目的:让每个业务组件可以通过统一一样的方法获取store的数据
    const context = React.createContext(rootStore);
    
    //通过useContext拿到rootStore实例对象,然后返回给useStore
    //导出useStore方法,供组件通过调用该方法使用根实例
    //在业务组件中 调用useStore()->rootStore
    const useStore = () => React.useContext(context);
    export { useStore };
    
    //以上是模板代码,在不同项目都通用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

组件中使用mobx

例如:在Login组件中使用

import { useStore } from '@/store'
const Login = () => {
  //解构出useStore模块
  const { useStore} = useStore()
  //调用useStore模块的addUse方法
  useStore.addUse ()
  return (...)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

十、项目本地预览


项目经过打包过后,往往需要本地预览服务端运行时的效果:

  1. 全局安装本地服务包 npm i -g serve 该包提供了serve命令,用来启动本地服务
  2. 在项目根目录中执行命令 serve -s ./build 在build目录中开启服务器
  3. 在浏览器中访问:http://localhost:3000/ 预览项目

十一、 打包体积分析


  1. 安装分析打包体积的包:npm i source-map-explorer

  2. package.json 中的 scripts 标签中,添加分析打包体积的命令

    package.json 中:

    "scripts": {
      "analyze": "source-map-explorer 'build/static/js/*.js'",
    }
    
    • 1
    • 2
    • 3
  3. 对项目打包:npm run build(如果已经打过包,可省略这一步)

  4. 运行分析命令:npm run analyze

  5. 通过浏览器打开的页面,分析图表中的包体积

十二、优化CDN配置

通过 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,配和public/index.html中配置使用
        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;
        },
    },
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

public/index.html

<body>
  <div id="root"></div>
    <!-- 加载第三发包的 CDN 链接 -->
    <% htmlWebpackPlugin.options.cdn.js.forEach(cdnURL=> { %>
        <script src="<%= cdnURL %>"></script>
        <% }) %>
</body>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/138918?site
推荐阅读
相关标签
  

闽ICP备14008679号