写点什么

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

  • 2022 年 9 月 14 日
    河南
  • 本文字数:6083 字

    阅读完需:约 20 分钟

【React】从0到1搭建你的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        项目入口
复制代码

保留核心代码

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>}
复制代码

二、使用 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. 安装路由:npm i react-router-dom

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

  3. 分别在创建的两个目录中创建 index.js 文件,并创建一个简单的组件后导出: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
复制代码


  1. App 组件中,导入路由组件以及两个页面组件

  2. 配置 LoginLayout 的路由规则

  3. 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. 安装:npm i history

  2. 创建 utils/history.js 文件

  3. 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. 在 app.js 中使用我们新建的路由并配置 history 参数

  2. app.js


  import { HistoryRouter, history } from './utils/history'    function App() {    return (      //HistoryRouter替换BrowserRouter      <HistoryRouter history={history}>         ...省略无关代码      </HistoryRouter>    )  }    export default App
复制代码


  1. 使用案例

  2. 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. 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
复制代码

五、组件库 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. 导入 Button 组件进行测试

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


  import { Button } from 'antd'    const Login = () => (    <div>      <Button type="primary">Button</Button>    </div>  )
复制代码


注意


  1. src/index.js文件中导入 antd 的样式文件

  2. antd 的样式文件和我们自己的全局样式文件的导入顺序

六、配置别名路径


安装 @craco/craco

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

  • CRA 将所有工程化配置,都隐藏在了 react-scripts 包中,所以项目中看不到任何配置信息

  • 如果要修改 CRA 的默认配置,有以下几种方案:

  • 通过第三方库来修改,比如,@craco/craco推荐

  • 通过执行 yarn eject 命令,释放 react-scripts 中的所有配置到项目中


  1. 安装修改 CRA 配置的包:npm i -D @craco/craco

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

  3. craco.config.js


  const path = require('path')    module.exports = {    // webpack 配置    webpack: {      // 配置别名      alias: {        // 约定:使用 @ 表示 src 文件所在路径        '@': path.resolve(__dirname, 'src')      }    }  }
复制代码


  1. 修改 package.json 中的脚本命令

  2. package.json


  // 将 start/build/test 三个命令修改为 craco 方式  "scripts": {    "start": "craco start",    "build": "craco build",    "test": "craco test",    "eject": "react-scripts eject"  }
复制代码


  1. 在代码中,就可以通过 @ 来表示 src 目录的绝对路径

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

@别名路径提示

  1. 在项目根目录创建 jsconfig.json 配置文件

  2. 在配置文件中添加以下配置


  {      "compilerOptions": {      "baseUrl": "./",      "paths": {        "@/*": ["src/*"]      }    }  }
复制代码


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

七、安装 dev-tools 调试工具


Edge插件下载链接


八、封装 axios 工具模块


  1. 安装axios :npm i axios

  2. 创建 utils/http.js 文件

  3. 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. utils/index.js 中,统一导出 http

  2. utils/index.js


  import { http } from './http'  export {  http }
复制代码

九、使用 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. store文件下创建index.js统一导出store

  2. 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 };    //以上是模板代码,在不同项目都通用
复制代码

组件中使用 mobx

例如:在Login组件中使用


import { useStore } from '@/store'const Login = () => {  //解构出useStore模块  const { useStore} = useStore()  //调用useStore模块的addUse方法  useStore.addUse ()  return (...)}
复制代码

十、项目本地预览


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


  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 标签中,添加分析打包体积的命令

  3. package.json 中:


  "scripts": {    "analyze": "source-map-explorer 'build/static/js/*.js'",  }
复制代码


  1. 对项目打包:npm run build(如果已经打过包,可省略这一步)

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

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

十二、优化 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; }, },};
复制代码


public/index.html


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


发布于: 2022 年 09 月 14 日阅读数: 26
用户头像

前端之行,任重道远! 2022.08.25 加入

本科大三学生、CSDN前端领域新星创作者、华为云享专家、第十三届蓝桥杯国赛三等奖获得者

评论

发布
暂无评论
【React】从0到1搭建你的React18项目_前端_海底烧烤店ai_InfoQ写作社区