react项目搭建

241 阅读4分钟

一、搭建项目

项目创建

npx create-react-app  项目名

清理项目多余文件

引入文件.prettierrc.json
{
  "singleQuote": true,
  "semi": false,
  "bracketSpacing": true,
  "htmlWhitespaceSensitivity": "ignore",
  "endOfLine": "auto",
  "trailingComma": "all",
  "tabWidth": 2
}
引入重置样式文件 reset.css
/* 重置reseet */
html, body, h1, h2, h3, h4, h5, h6, div, dl, dt, dd, ul, ol, li, p, blockquote, pre, hr, figure, table, caption, th, td, form, fieldset, legend, input, button, textarea, menu {
    margin: 0;
    padding: 0;
  }
  
  header, footer, section, article, aside, nav, hgroup, address, figure, figcaption, menu, details {
    display: block;
  }
  
  table {
    border-collapse: collapse;
    border-spacing: 0;
  }
  
  caption, th {
    text-align: left;
    font-weight: normal;
  }
  
  html, body, fieldset, img, iframe, abbr {
    border: 0;
  }
  
  html {
    font-family: sans-serif;
  }
  
  i, cite, em, var, address, dfn {
    font-style: normal;
  }
  
  [hidefocus], summary {
    outline: 0;
  }
  
  li {
    list-style: none;
  }
  
  h1, h2, h3, h4, h5, h6, small {
    font-size: 100%;
  }
  
  sup, sub {
    font-size: 83%;
  }
  
  pre, code, kbd, samp {
    font-family: inherit;
  }
  
  q:before, q:after {
    content: none;
  }
  
  textarea {
    overflow: auto;
    resize: none;
  }
  
  label, summary {
    cursor: default;
  }
  
  a, button {
    cursor: pointer;
  }
  
  h1, h2, h3, h4, h5, h6, em, strong, b {
    font-weight: bold;
  }
  
  del, ins, u, s, a, a:hover {
    text-decoration: none;
  }
  
  body, textarea, input, button, select, keygen, legend {
    font: 14px/1.14 arial,\5b8b\4f53;
    color: #333;
    outline: 0;
  }
  
  body {
    background: #fff;
  }
  
  a, a:hover {
    color: #333;
  }
在index.js引入
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './reset.css'     //引入重置样式

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

引入sass

npm i sass
创建views/Home/index.jsx的单独scss文件
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { plus } from '@/store/slice/counter'

import styles from './index.module.scss'  //引用

import { Button } from 'antd'

export default function Index() {
    const num = useSelector(state => state.counter.count)
    const dispatch = useDispatch()
    return (
        <div>
            <h2 className={styles['title']}>主界面Home</h2> //使用
            <p>num: {num}</p>
            <button
                onClick={() => {
                    dispatch(plus())
                }}
            >
                加一
            </button>
            <Button type="primary">Primary Button</Button>
        </div>
    )
}

views/Home/index.module.scss

.title{
    color: blueviolet;
}

路由

npm i react-router-dom@6.4.3  
创建文件views

About/index.jsx

import React from "react";

export default function Index() {
  return (
    <div>
      <p>路由1</p>
    </div>
  );
}

Home/index.jsx

import React from "react";

export default function Index() {
  return (
    <div>
      <p>路由2</p>
    </div>
  );
}
创建路由文件router/index.jsx
import React from 'react'
import { BrowserRouter, Routes, Route, NavLink,Navigate } from 'react-router-dom'
import About from '../views/About'
import Home from '../views/Home'

export default function Index() {
    return (
        <BrowserRouter>
            <NavLink to="/about">关于</NavLink> | <NavLink to="/home">home</NavLink>
            <Routes>
               <Route index element={<Navigate to='/about'></Navigate>}></Route>
                <Route path="/about" element={<About />}></Route>
                <Route path="/home" element={<Home />}></Route>
            </Routes>
        </BrowserRouter>
    )
}
在app.js引入router/index.js
import Router from './router'

function App() {
    return <Router></Router>
}

export default App

redux状态管理

npm i redux@4.1.1 --save 
npm i redux-thunk@2.4.1
npm i @reduxjs/toolkit@1.9.0
npm install react-redux
或者:
npm i react-router-dom@6.4.3   redux@4.2.0  @reduxjs/toolkit@1.9.0 react-redux@8.0.5  -D
创建stroe/index.jsx
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './slice/counter'
export default configureStore({
    reducer: {
        counter: counterReducer,
    },
})
创建stroe/slice/counter.jsx
import { createSlice } from '@reduxjs/toolkit'

const counterSlice = createSlice({
    name: 'counter',
    initialState: {
        count: 0,
    },
    reducers: {
        plus: state => {
            state.count += 1
        },
    },
})
export const { plus } = counterSlice.actions
export default counterSlice.reducer
在views/Home/index.jsx中使用
import React from 'react'

import { useSelector, useDispatch } from 'react-redux'   //使用
import { plus } from '@/store/slice/counter'

import styles from './index.module.scss'
import { Button } from 'antd'

export default function Index() {
    
    const num = useSelector(state => state.counter.count)
    const dispatch = useDispatch()
    
    return (
        <div>
            <h2 className={styles['title']}>主界面Home</h2>
            <p>num: {num}</p>
            <button
                onClick={() => {
                    
                    dispatch(plus())   //使用
                    
                }}
            >
                加一
            </button>
            <Button type="primary">Primary Button</Button>
        </div>
    )
}

引入antd组件

npm i antd@4.24.5

引人axios库

npm i axios 
创建api文件

axios二次封装api/ request.js

import axios from 'axios'
import {message} from 'antd'

// export const baseURL = 'http://43.136.34.132:8088'
export const baseURL = 'http://localhost:3000'
// 创建axios新实例
const axiosInstance = axios.create({
    baseURL, // 接口根地址
    // baseURL: 'http://localhost:8080', // 接口根地址
    timeout: 3000, // 超时时间
})


/**
 * 请求拦截器
 */
axiosInstance.interceptors.request.use(
    config => {
        // 发起请求之前做一些处理
        const token = localStorage.getItem('TOKEN')
        if(token){
            config.headers['Authorization'] = token
        }

        return config
    },
    err => Promise.reject(err)
)

/**
 * 响应拦截器
 */
axiosInstance.interceptors.response.use(
    res => {
        // 响应数据做一些处理
        // console.log('响应数据 res ', res)
        return res.data
    },
    error => {
        const { response } = error
        if (response) {
            const status = response.status
            switch (status) {
                case 404:
                    message.error('资源不存在 404')
                    break
                case 401:
                    message.error('Unauthorized 身份验证凭证缺失!')
                    break
                case 403:
                    message.error('403 Forbidden - 拒绝访问!')
                    break
                case 500:
                    message.error('服务器出错')
                    break
                default:
                    message.error('出现异想不到的错误!')
                    break
            }
        } else {
            // 说明服务器连结果都没有返回,可能的原因有两种:
            /**
             * 1. 服务器崩掉了
             * 2. 前端客户端断网状态
             */
            if (!window.navigator.onLine) {
                // 判断为断网,可以跳转到断网页面
                message.error('网络不可用,请检查您的网络连接!')
                return
            } else {
                message.error('连接服务端出错!' + error?.message)
                return Promise.reject(error)
            }
        }
        return Promise.reject(error)
    }
)

export default axiosInstance
使用实例化
import axiosInstance from '../request'

/**
 * 登录接口
 */
export const RequestLogin = (username, password) => {
    return axiosInstance({
        method: 'post',
        url: '/api/login',
        data: {
            username,
            password,
        },
    })
}

react配置文件

npm i react-app-rewired@2.2.1 customize-cra@1.0.0 -D

创建config-overrides.js

const { override, addWebpackAlias } = require('customize-cra')
const path = require('path')

module.exports = override(
    // 路径别名
    addWebpackAlias({
        '@': path.resolve(__dirname, 'src'),
    })
)
修改package.json
"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  
  改为:
   "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  },
配置代理
npm i http-proxy-middleware@2.0.6 --save-dev

创建src/setupProxy.js

const { createProxyMiddleware } = require('http-proxy-middleware')
 
module.exports = function (app) {
    app.use(
        createProxyMiddleware('/api', {
            target: 'http://10.7.172.59:8089/',
            changeOrigin: true,
            // pathRewrite: {
            //   '^/api': ''
            // }
        })
    )
}

完成后的package.json

{
  "name": "react-app-template",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "antd": "^4.24.5",
    "axios": "^1.4.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@reduxjs/toolkit": "^1.9.0",
    "customize-cra": "^1.0.0",
    "http-proxy-middleware": "^2.0.6",
    "react-app-rewired": "^2.2.1",
    "react-redux": "^8.0.5",
    "react-router-dom": "^6.4.3",
    "redux": "^4.2.0",
    "sass": "^1.63.6"
  }
}