创建好 Create React App dome 项目后完成如下操作, 让你的后续工作更丝滑
1 . 调整目录结构
├── src
│ ├── App.js # 根组件
│ ├── index.css # 全局样式
│ ├── index.js # 项目入口
│ ├── api # axios 请求
│ ├── assets # 项目资源文件,比如,图片 等
│ ├── components # 通用组件
│ ├── pages # 页面
│ └── utils # 工具,比如,token、axios 的封装等
└── package-lock.json
2 . 调整文件内容
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(
<App />,
document.getElementById('root')
)
3 . 配置路由
安装路由
react
脚手架并没有默认集成路由功能,需要单独安装。
安装路由 :
npm i react-router-dom@5.3.0
注意 :
目前6.0.0以上版本的路由生态不完善, 占时不推荐使用
排期
按照页面A 和页面B 没有相同的部分,这两个页面就应该是一级路由的思路配置路由
路由地址 --------- 页面组件
1级路由
localhost:3000/layout -----> pages/Layout/Layout.jsx
localhost:3000/login -----> pages/Login/Login.jsx
localhost:3000/其他地址 -----> pages/NotFound/NotFound.jsx
2级路由
localhost:3000/layout/questions -----> pages/Layout/Questions/Question.jsx
localhost:3000/layout/column -----> pages/Layout/Column /Column .jsx
localhost:3000/layout/course -----> pages/Layout/Course /Course .jsx
localhost:3000/layout/activity-----> pages/Layout/Activity/Activity.jsx
创建必备组件
src
└── pages
├── Layout
│ └── Layout.jsx
├── Login
│ └── Login.jsx
└── NotFound
└── NotFound.jsx
配置路由组件
App.js 组件中
- 导入路由组件
- 导入页面组件
- 配置路由规则
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>
)
}
4 . 配置第三方组件库 antd
下载依赖包
-
npm i antd
或
yarn add antd
在 index.js 中导入 antd 的样式文件
// 在 index.js 中导入 antd 的样式文件
import 'antd/dist/antd.css'
5 . 二次封装 axios
下载依赖包
-
npm i axios
或
yarn add axios
在 utils 下建立
request.js
工具文件
完成如下配置 :
- 配置基地址
- 请求等待时间
- 添加请求拦截器&响应拦截器
- 导出 封装后的 axios
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
api/login.js
文件导入
request
封装 api
6 . sass的使用
注意:
在
react
脚手架中已集成了
sass
的配置,因此只需要安装
sass
的依赖包,就可以直接使用sass了
安装
sass
依赖包
-
npm i sass -D
或
yarn add
使用 :
-
把
index.css
改成
index.scss
-
在组件中导入
index.scss
文件
7 . 修改 @ 为src路径
cra脚手架 中 修改 @ 为src路径
-
下包
yarn add -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" },
注意 : eject 命令是强制释放所有配置,到
react-scripts
文件中, 这个命令是不可逆的不推荐使用
8 . 使用 @ 后vscode 提示配置
-
新建
jsconfig.json
文件{ "compilerOptions": { "baseUrl": "./", "paths": { "@/*": ["src/*"] } } }
9 . 样式污染解决方法
前提 :
如果多个组件的样式中出现选择器重复,那么一个组件中的样式就会在另一个组件中也生效,从而造成组件之间样式相互覆盖的问题。
方法一
(不推荐)
给每个组件的根标签取不一样的类名
方法二 CSS IN JS (推荐使用)
CSS IN JS :
是使用 JavaScript 编写 CSS 的统称,用来解决 CSS 样式冲突、覆盖等问题
具体实现方法有50种(下述为常用的两种)
- scoped : vue中默认使用 scoped css
-
CSS Moudles
: React 中默认使用 CSS Moudles
10 .
CSS Moudles
的使用
-
在所有的css的文件名后缀前面加上
.moudle
-
组件中, 导入
import styles from './xxx.module.scss
-
组件中使用 :
<div className={style.css类名}>
注意 :
-
CSS Moudles 最好使用 驼峰命名
-
保持原有类名的语法
:global(.类名){样式}
-
应用场景 : 修改别人已经封装好组件的类名(
组件库-antd
)
-
应用场景 : 修改别人已经封装好组件的类名(
11 . CSS Modules 的简化用法
上述用法写类名有点麻烦
简化用法
-
定义样式, 在根节点下用
:global {}
包裹 -
组件中使用方法
-
根节点用
<div className={style.css类名}>
-
子节点用 直接使用类名
className=css类名
-
根节点用
12 . 配置 Redux
-
安装 redux 相关的包:
npm i redux react-redux redux-thunk redux-devtools-extension
- 在 store 目录中分别创建:actions 和 reducers 文件夹、index.js 文件
- 在 store/index.js 中,创建 store 并导出
- 创建 reducers/index.js 文件,创建 rootReducer 并导出
- 创建 reducers/login.js 文件,创建基础 login reducer 并导出
- 在 src/index.js 中为 React 组件接入 Redux
store 目录结构:
├─store # redux根目录
│ ├─actionTypes.js #
│ ├─reducers #
│ │ ├─index.js #
│ │ └─login.js #
│ ├─actions #
│ │ └─login.js #
│ └─index.js # 创建store并导出
配置代码直接开箱即用
store/index.js 中:
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import rootReducer from './reducers'
const middlewares = composeWithDevTools(applyMiddleware(thunk))
const store = createStore(rootReducer, middlewares)
export default store
store/reducers/index.js 中:
import { combineReducers } from 'redux'
import login from './login'
const rootReducer = combineReducers({
login
})
export default rootReducer
store/reducers/login.js 中:
const initValue = {
token: ''
}
export default function login(state = initValue, action) {
return state
}
src/index.js 中:
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
13 . AuthRoute 组件封装
实现 React 中路由权限控制
components/AuthRoute .js
import { hasToken } from '@/utils/storage'
import React from 'react'
import { Route, Redirect } from 'react-router-dom'
// 我们需要解构所有的属性,除了component属性
export default function PrivateRoute(porps) {
const Component = porps.component
return (
<Route
{...porps}
//path = {porps.path} 子组件内部没有 porps参数
render={() => {
if (hasToken()) {
return <Component></Component>
} else {
return <Redirect to="/login"></Redirect>
}
}}
></Route>
)
}
app.js
import PrivateRoute from './components/AuthRoute '
<PrivateRoute path="/home" component={组件名}></PrivateRoute>