一、项目搭建(不采用vite方式)
-
使用create-react-app生成项目
npx create-react-app pc
-
进入根目录
cd pc
-
启动项目 npm
start
-
调整项目目录结构
/src /assets 项目资源文件,比如,图片 等 /components 通用组件 /pages 页面 /store mobx 状态仓库 /utils 工具,比如,token、axios 的封装等 App.js 根组件 index.css 全局样式 index.js 项目入口
5. 整理生成的文件
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>
}
6.安装scss预处理器
npm i sass -D
创建全局样式文件:index.scss
body {
margin: 0;
}
#root {
height: 100%;
}
7.配置路由
npm i react-router-dom -S
实现步骤
- 安装路由:
yarn add react-router-dom
- 在 pages 目录中创建两个文件夹:Login、Layout
- 分别在两个目录中创建 index.js 文件,并创建一个简单的组件后导出
- 在 App 组件中,导入路由组件以及两个页面组件
- 配置 Login 和 Layout 的路由规则
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 path="/login" element={<Login/>}/>
</Routes>
</div>
</BrowserRouter>
)
}
export default App
8.安装组件库antd
npm i antd -S
src/index.js
import 'antd/dist/antd.min.css'
// 再导入全局样式文件,防止样式覆盖!
import './index.css'
9.配置别名路径
CRA 将所有工程化配置,都隐藏在了 react-scripts 包中,所以项目中看不到任何配置信息
如果要修改 CRA 的默认配置,有以下几种方案:
通过第三方库来修改,比如,@craco/craco (推荐)
通过执行 yarn eject 命令,释放 react-scripts 中的所有配置到项目中
实现步骤
- 安装修改 CRA 配置的包:
yarn add -D @craco/craco
- 在项目根目录中创建 craco 的配置文件:
craco.config.js
,并在配置文件中配置路径别名 - 修改
package.json
中的脚本命令 - 在代码中,就可以通过
@
来表示 src 目录的绝对路径 - 重启项目,让配置生效
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"
}
@别名配置
实现步骤
- 在项目根目录创建
jsconfig.json
配置文件 - 在配置文件中添加以下配置
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
}
}
vscode会自动读取jsconfig.json
中的配置,让vscode知道@就是src目录
二、项目搭建(采用vite方式)
1、通过脚手架安装
1.1、或者使用npm init vite@latest
2、配置vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
export default defineConfig({
server:{
host: '0.0.0.0',
port: 3000,
strictPort: false,
https: false,
open: true,
proxy: {
'/api': {
target: '后端接口域名',
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/api/, ''),
}
}
},
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'), // src 路径
}
},
plugins: [react()],
})
3、安装scss
npm install sass --save
yarn add sass
4、安装路由
npm i react-router-dom --save
或者
yarn add react-router-dom
然后进行引入配置
方式一:
## main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter, Routes } from "react-router-dom";
import App from './App'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
)
##app.jsx
import { Routes} from "react-router-dom";
import routes from '@/router/index'
function App() {
return (
<Routes>
{routes}
</Routes>
)
}
export default App
创建router/index.jsx文件
import { Route, Navigate } from "react-router-dom";
import Index from '@/pages/index.jsx'
export default [
<Route key="Navigate" path="*" element={<Navigate to="/"/>} />,//重定向到首页
<Route key="Index" path="/" element={ <Index/>} />
]
方式二(推荐):使用useRoutes
## main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from "react-router-dom";
import App from './App'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
)
## app.jsx
import { useRoutes } from "react-router-dom";
import routes from '@/router/index.jsx'
function App() {
const element = useRoutes(routes);
return (
<>
{element}
</>
)
}
export default App
创建router/index.jsx
import { Navigate } from 'react-router-dom'
import Index from '@/pages/index'
// const My = lazy(()=>import('@/views/My')); //路由懒加载
const router = [
{
path: "/",
element: <Index />,
children: [
// 二级路由...
]
},
// {
// path: "/my",
// element: <My />
// },
// 配置路由重定向 可配置404页面
{
path: '*',
element: <Navigate to='/' />
}
]
export default router
5、添加环境变量文件
.env.development
NODE_ENV = 'development'
VITE_APP_ENV = 'development'
VITE_APP_BASE_API = '接口请求的域名'
VITE_APP_BASE_Images = '图片路径'
.env.production
NODE_ENV = 'production'
VITE_APP_ENV = 'production'
VITE_APP_BASE_API = '接口请求的域名'
VITE_APP_BASE_Images = '图片路径'
使用环境变量
import.meta.env.VITE_APP_BASE_API
6、使用axios
npm install axios --save
或者
yarn add axios
可以自定义封账axios,创建utils/request.js
import axios from 'axios'
// create an axios instance
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API, // url = base url + request url
withCredentials: false, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
// request interceptor
service.interceptors.request.use(
config => {
// 做一些请求前置,例如添加token
// config.headers['token'] = getToken()
return config
},
error => {
console.log(error)
return Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
response => {
const res = response.data
// if the custom code is not 200, it is judged as an error.
if (res.code == 1||res.code == 0) {
// 配置响应拦截
return res
} else {
return Promise.reject(new Error(res.msg || '网络异常,请稍后~'))
}
},
error => {
console.log(error)
return Promise.reject(error)
}
)
export default service
使用utils/request.js
import request from '@/utils/request' // 其他引入文件
export default class Index extends React.Component{
constructor(props) {
super(props)
request.get('/article/getAll').then(res => {
console.log(res)
})
}
}
7、 使用redux( redux官方文档:快速开始 | Redux 中文官网)
安装redux
npm install @reduxjs/toolkit react-redux --save
yarn global add @reduxjs/toolkit react-redux
修改main.jsx文件
/* 其他引入的js不变,只是新增这2个插件 */
import store from '@/store/index'
import { Provider } from 'react-redux'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</React.StrictMode>
)
如果使用了路由懒加载
import React, { Suspense } from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from "react-router-dom";
import store from '@/store/index'
import { Provider } from 'react-redux'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<Provider store={store}>
<Suspense fallback={<div>Loading...</div>}>
<BrowserRouter>
<App />
</BrowserRouter>
</Suspense>
</Provider>
</React.StrictMode>
)
创建store/index.js文件
import { configureStore } from "@reduxjs/toolkit";
// configureStore 创建一个 redux 数据
const store = configureStore({
reducer: {
},
});
export default store;
创建store/modules/counterSlice.js测试文件(官方例子)
import { createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
increment: state => {
// Redux Toolkit 允许我们在 reducers 写 "可变" 逻辑。它
// 并不是真正的改变状态值,因为它使用了 Immer 库
// 可以检测到“草稿状态“ 的变化并且基于这些变化生产全新的
// 不可变的状态
state.value += 1
},
decrement: state => {
state.value -= 1
},
incrementByAmount: (state, action) => {
state.value += action.payload
}
}
})
// 每个 case reducer 函数会生成对应的 Action creators
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer
将counterSlice挂载到store/index.js里面
/* 其他引入的插件不需要变,新增这个引入 */
import counterReducer from '@/store/modules/counterSlice'
// configureStore 创建一个 redux 数据
const store = configureStore({
reducer: {
counter: counterReducer
},
});
export default store;
函数组件中 使用redux
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from '@/store/modules/counterSlice'
export default function Index(){
const count = useSelector(state => state.counter.value)
const dispatch = useDispatch()
return (
<div>
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Increment
</button>
<span>{count}</span>
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Decrement
</button>
</div>
</div>
)
}
类组件中使用redux
import { connect } from'react-redux'
import { incrementByAmount } from "@/store/modules/userStore";
class NavbarHeader extends React.Component{
state={
}
componentDidMount(){
console.log(this.props.value)
// this.props.incrementByAmount("sjgdsjd"); //使用
}
}
const mapStateToProps = (state) => {
return {
value: state.userStore.value
};
};
const mapDispatchToProps = {
incrementByAmount
};
export default connect(mapStateToProps,mapDispatchToProps)(Index);
8、使用ant-design UI
npm install antd --save
import { DatePicker } from 'antd';
export default () => {
return (
<DatePicker />
)
}
使用icon
npm install @ant-design/icons --save
import { CalendarOutlined } from '@ant-design/icons';
<CalendarOutlined style={{ fontSize: 16, color: '#333' }} />