React18 + TS 模版搭建
配置 React18 + TS 的项目模版和代码规范, 让你的后续工作更丝滑。
安装
create-react-app
Getting Started | Create React App (create-react-app.dev)
npx create-react-app git-blog --template typescript
cd git-blog
npm start
QA
- 如何安装指令版本?
npm install react@17.x react-dom@17.x --save
- Jsx 文件报错?
- ts项目安装后 删除
node_modules
,重新npm install
, 不然jsx会报错; tsconfig.json
文件中,启用--jsx
标志;"jsx": "react-jsx"
修改为"jsx": "react"
;
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react" // 新增jsx 编译
},
"include": ["src"]
}
目录结构调整
目录规范
├── src
│ ├── api # axios 请求
│ ├── assets # 项目资源文件,比如,图片 等
│ ├── components # 通用组件
│ ├── pages # 页面
│ ├── router # 路由
│ ├── store # store
│ ├── style # 全局样式
│ ├── utils # 工具,比如,token、axios 的封装等
│ ├── App.tsx # 根组件
│ ├── index.tsx # 项目入口
│ ├── react-app-env.d.ts
│ ├── reportWebVitals.ts
QA
react < 18
的版本,src/index.tsx
修改为:
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(
<App />,
document.getElementById('root')
)
路由
V6
createBrowserRouter vv6.3.0 | React Router
npm i react-router-dom
V6 提供配置化路由。
router/index.tsc
import React from 'react'
import {createBrowserRouter, Link} from 'react-router-dom'
const router = createBrowserRouter([
{
path: '/',
element: (
<div>
<h1>Hello World</h1>
<Link to="about">About Us</Link>
</div>
)
},
{
path: 'about',
element: <div>About</div>
}
])
export default router
App.tsx
import React from 'react'
import './style/App.css'
import {RouterProvider} from 'react-router-dom'
import router from './router'
function App() {
return <RouterProvider router={router} />
}
export default App
QA
react-router V5 配置路由规则。
import React from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import Login from './pages/Login/Login.jsx'
import Layout from './pages/Layout/Layout.jsx'
import NotFound from './pages/NotFound/NotFound.jsx'
export default function App() {
return (
<Router>
<div className="app">
<Switch>
<Route path="/login" component={Login}></Route>
<Route path="/layout" component={Layout}></Route>
{/* 增加一个404 */}
<Route component={NotFound}></Route>
</Switch>
</div>
</Router>
)
}
ArcoDesign 组件库
npm i @arco-design/web-react
App.tsx
import React from 'react'
import './style/App.css'
import {RouterProvider} from 'react-router-dom'
import router from './router'
import {Button} from '@arco-design/web-react'
import '@arco-design/web-react/dist/css/arco.css'
function App() {
return (
<div>
<RouterProvider router={router} />
<Button type="primary">Hello Arco</Button>
</div>
)
}
export default App
axios
axios中文网|axios API 中文文档 | axios (axios-js.com)
npm i axios
util/http.js
import axios from 'axios'
// baseURL设置/超时时间设置
const instance = axios.create({
baseURL: 'http://xxx.xxx.xx', // 配置请求基地址
timeout: 5000 // 配置等待时间
})
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
// 操作请求
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 操作响应
return response.data
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error)
})
/**
* @param {String} - url 请求地址
* @param {String} - method 请求类型
* @param {Object} - submitData 对象类型,提交数据
*/
const request = (url, method, submitData) => {
return instance({
url,
method,
[method.toLowerCase() === 'get' ? 'params' : 'data']: submitData
})
}
export default request
sass
在 react
脚手架中已集成了sass
的配置,因此只需要安装 sass
的依赖包,就可以直接使用sass。
npm i sass -D
修改 @为src路径
npm i -D @craco/craco
- 在项目根目录下,创建配置文件:
craco.config.js
// craco.config.js
const path = require('path')
module.exports = {
webpack: {
alias: {
'@': path.join(__dirname, 'src') // 允许通过@符号来表示 src目录
}
}
}
- 修改
package.json
中的脚本命令
// 将 start/build/test 三个命令修改为 craco 方式
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
},
- 配置 vscode 使用
@
提示
jsconfig.json
或tsconfig.json
新增,我们使用的是TS环境,配置tsconfig.json
。
{
"compilerOptions": {
"baseUrl": "./", // 新增:配置 vscode 使用 @提示
"paths": {
"@/*": ["src/*"] // 新增:配置 vscode 使用 @提示
},
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react" // 新增:jsx 编译
},
"include": ["src"]
}
样式解决方案
如果多个组件的样式中出现选择器重复,那么一个组件中的样式就会在另一个组件中也生效,从而造成组件之间样式相互覆盖的问题?
- 方法一 (不推荐)
给每个组件的根标签取不一样的类名。
- 方法二 CSS IN JS (推荐使用)
CSS IN JS : 是使用 JavaScript 编写 CSS 的统称,用来解决 CSS 样式冲突、覆盖等问题。
具体实现方法有50种(下述为常用的两种)。
- scoped : vue中默认使用 scoped css
- CSS Moudles : React 中默认使用 CSS Moudles
CSS Modules 的使用
用法:
- 在所有的css的文件名后缀前面加上
.moudle
- 组件中, 导入
import styles from './xxx.module.scss
- 组件中使用 :
<div className={styles.css类名}>
简化用法:
-
定义样式, 在根节点下用
:global {}
包裹 -
组件中使用方法
- 根节点用
<div className={style.css类名}>
- 子节点用 直接使用类名
className=css类名
- 根节点用
注意 :
-
CSS Moudles 最好使用
驼峰命名
-
保持原有类名的语法
:global(.类名){样式}
- 应用场景 : 修改别人已经封装好组件的类名(组件库-antd)
QA
- CSS Modules 配置vscode代码提示?
- 安装依赖
npm install typescript-plugin-css-modules -D
- 在
tsconfig.json
中配置插件的使用
{
"compilerOptions": {
...
// 添加下面配置
"plugins": [
{
"name": "typescript-plugin-css-modules"
}
]
},
"include": [
"src"
]
}
- 在项目的根目录新建
.vscode/settings.json
,配置vscode的配置
// .vscode/settings.json文件中
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
- 创建文件
src/types/custom.d.ts
declare module "*.css" {
const css: { [key: string]: string };
export default css;
}
Redux配置
Redux
- 安装
npm i redux react-redux redux-thunk redux-logger @types/redux-logger
npm install redux-devtools-extension --save-dev
- store 目录结构
├─store # redux根目录
│ ├─reducers
│ │ ├─index.js
│ │ └─student.js
│ ├─actions
│ │ └─student.js
│ └─index.js # 创建store并导出
action/student.js
export const actionTypes = {
//设置学生查询结果数组和总数
setStudentsAndTotal: 'setStudentsAndTotal'
}
export function setStudentsAndTotal(arr, total) {
return {
type: actionTypes.setStudentsAndTotal,
payload: {
datas: arr,
total
}
}
}
store/reducers/index.js
// 创建一个唯一的reducer
import students from './student'
import {combineReducers} from 'redux'
export default combineReducers({
students
})
store/reducers/student.js
import {actionTypes} from '@/store/action/student'
// 默认状态
const initialState = {
datas: [],
total: 0
}
/**
* 控制查询结果的reducer
* @param {*} state
* @param {*} action
*/
export default function (state = initialState, {type, payload}) {
switch (type) {
case actionTypes.setStudentsAndTotal:
return {
...state,
...payload
}
default:
return state
}
}
store/index.js
// 用于创建仓库,并导出
import {createStore, applyMiddleware} from 'redux'
import reducer from './reducer'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
// 安装redux-devtools-extension的可视化工具。
import {composeWithDevTools} from 'redux-devtools-extension'
const store = createStore(
reducer,
composeWithDevTools(applyMiddleware(thunk, logger))
)
export default store
src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import './style/index.scss'
import App from '@/App'
import reportWebVitals from './reportWebVitals'
import {Provider} from 'react-redux'
import store from './store'
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
root.render(
<Provider store={store}>
<App />
</Provider>
)
reportWebVitals()
App.tsx
测试
import React, {useEffect} from 'react'
import '@/style/App.scss'
import {RouterProvider} from 'react-router-dom'
import router from './router'
import {Button} from '@arco-design/web-react'
import '@arco-design/web-react/dist/css/arco.css'
import {useSelector, useDispatch} from 'react-redux'
import {setStudentsAndTotal} from '@/store/action/student'
function App() {
const data = useSelector((state) => {
return state
})
const dispatch = useDispatch()
console.log(data)
useEffect(() => {
dispatch(setStudentsAndTotal([1, 2, 3], 3))
console.log('setStudentsAndTotal', data)
}, [])
return (
<div>
<RouterProvider router={router} />
<Button type="primary">Hello Arco</Button>
</div>
)
}
export default App
QA
Redux - A predictable state container for JavaScript apps. | Redux
Getting Started with React Redux | React Redux (react-redux.js.org)
Redux DevTools 扩展的使用说明 - 掘金 (juejin.cn)
模版地址
PantherVkin/react-ts-project-template: React18 项目模版 (github.com)