【React】從 0 到 1 搭建你的 React18 專案

語言: CN / TW / HK

一,專案搭建

安裝腳手架 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>  )

複製程式碼

注意

src/index.js
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>

複製程式碼