我都配置了什么呢?

前言

在开发日常项目时,每次create-react-app后都要做一些重复性修改,比如说添加less的支持或者添加装饰器的支持,还有假如react-router或者redux的支持,于是这次将他们一次性封装完成,下次再次启动新项目时,就直接从自己的仓库中clone来开发就好。

弹出自定义配置

这是自定义cli的基础,以便我们修改cli的部分文件,记住又一个坑,必须要先git add . 和 git commit 后才能进行,要不然npm直接会报错。
运行npm run eject,操作之前切记需要git commit

热加载

一直很疑惑这个功能为啥原生脚手架不自动开启,对于我这种对css有极度强迫症的人来说,修改一点css后瞬间出效果,而不要再次刷新页面,简直提高了很多效率。

index.js最后添加

1
2
3
if (module.hot) {
module.hot.accept();
}

添加路由

这是开发SPA的基础,但是在实际开发过程中,this.props.history并不是在所有js文件中都能使用的,比如说在redux和封装的axios中,因为一般redux都是和组件拆分的,所以在antion函数中并不存在this.props.history这个对象,那怎么解决呢,在github上找到一个黑科技的解决方案,只要引入自己设置的history,无论是在哪里,都不需要用this.pros.history,直接使用自己封装的history,具体步骤如下:

  1. 下载router包

npm i react-router-dom -S

  1. 在src中的config文件夹下创建history.js
1
2
3
import createHistory from 'history/createBrowserHistory';

export default createHistory();
  1. 在index.js中引入
1
2
import { BrowserRouter, Router } from "react-router-dom";
import history from "./config/history"
  1. 将App组件被路由所包裹
1
2
3
4
5
6
7
8
ReactDOM.render(
<BrowserRouter>
<Router history={history}>
<App />
</Router>
</BrowserRouter>,
document.getElementById("root")
);
  1. 在container中创建Index组件,并在app.js中添加以下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, { Component } from 'react';
import { Route, Switch, withRouter} from 'react-router-dom';

import Index from './container/index'

@withRouter
class App extends Component {
render() {
return (
<div>
<Switch>
<Route exact path="/" component={Index}></Route>
</Switch>
</div>
);
}
}

export default App;

封装axios配置

记得刚刚入门的时候,对axios的使用基本上就停留在他的promise中,虽然听说过axios还有拦截器这一操作,但是一直未尝试,后来在开发中,实在忍受不了每个请求都要手动加上token,每个返回结果都要判断是否需要弹出错误提醒和请求超时再次重新请求,后来发现axios拦截器真是个神器,于是就在每次开启新的项目中,都先配置axios拦截,妈妈再也不需要担心我写多余重复的代码啦~

  1. 下载必要包
    npm i axios

  2. 在config文件夹中添加axios.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import axios from 'axios'

import { getCookie } from "../config/token"
import history from "../config/history"

const instance = axios.create({
timeout: 5000,
baseURL: 'http://localhost:3067'
})
instance.interceptors.request.use(
req => {
// const token = getCookie('token')
// // 公共请求API,请求头不带有Authorization
// const publicUrl = ["/signup", "/signin", "/email/validate", "/user/reset", "/temp/all" ]
// const url = req.url
// // 其他需要Authorization的请求
// if (publicUrl.indexOf(url) === -1) {
// req.headers.Authorization = token
// if (!token){
// history.push('/login') // 当cookie中存储的token过期后自动跳转到登录页
// }
// }
return req
},
err => {
throw new Error('发起请求出错')
}
)

instance.interceptors.response.use(
res => {
return res
},
err => {
// 本地环境错误
if (err.message === "Network Error") {
throw new Error( '网络环境太差,请稍后再试!')
} else if (err.message === "timeout of 5000ms exceeded") {
throw new Error( '请求超时,请稍后再试!')
} else {
throw err // 非本地环境错误
}
}
)

export default instance

添加状态管理redux

redux在开发稍微复杂点的项目来说,提供了很多便利,所有的状态就在一个store中管理,将各个组件零零散散的状态集中起来,还能在各个组件中传递,这样在各个组件传递信息时候,就再也不需要写层层嵌套props的垃圾代码。

虽然前期学习成本有点高,但是领悟到了redux的思想后,便是一劳永逸,付出还是值得的。

  1. 安装必要包

npm i redux redux-thunk react-redux -S

  1. 在src中添加redux文件以及reducer.js文件夹

  2. redux中创建article.redux.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import axios from "../config/axios"

const GET_ARTICLE_DATA = "GET_ARTICLE_DATA"

const initState = {
total: 0,
items: []
}

export function article(state = initState, action) {
switch (action.type) {
case GET_ARTICLE_DATA:
return {...state, ...action.payload}
default:
return state
}
}

function getArticleSuccess(obj) {
return { type: GET_ARTICLE_DATA, payload: obj }
}

/**
* 获取所有文章数据
*/
export function getArticleData() {
return async dispatch => {
const getData = axios.get('/article/all/',{
params: {
page: 1,
pageSize: 10
}
})
try {
let result = await getData
if (result.status === 200) {
dispatch(getArticleSuccess(result.data.data))
}
} catch (e) {
console.log(e)
}
}
}
  1. reducer.js中将redux集合
1
2
3
4
5
import { combineReducers } from 'redux'

import { article } from "./redux/article.redux"

export default combineReducers({ article })
  1. 在index.js中引入必要文件
1
2
3
4
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { Provider } from "react-redux";
import reducers from "./reducer";
  1. 创建store
1
2
3
4
5
6
7
const store = createStore(
reducers,
compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f => f
)
)
  1. 将App组件被redux包围
1
2
3
4
5
6
7
<Provider store={store}>
<BrowserRouter>
<Router history={history}>
<App />
</Router>
</BrowserRouter>
</Provider>,

添加对装饰器的支持

第一次接触装饰器还是在阮大大中ES6入门上看到的,当时似懂非懂地理解,后来在实际项目中也没怎么用到过,直到后来在react-router中的withRouter用法时,才明白装饰器是怎么回事,但是目前脚手架原生并不支持,所以需要自己配置babel。

  1. 安装装饰器的babel

npm i babel-plugin-transform-decorators-legacy -D

  1. 在package.json中设置babel参数
1
2
3
4
5
6
7
8
"babel": {
"presets": [
"react-app"
],
"plugins": [
"transform-decorators-legacy"
]
}

配置less

这个就不用多说,less比起其他的预编译器来说,能够在其中写原生css,没有很多限制,并且也有其他预编译器的功能,所以是我期待的。

1.安装必要包

npm i less less-loader -D

2.修改根目录config中的webpack配置文件

1
2
3
4
5
6
7
{
test: /\.(css|less)$/,
use: [
{
loader: require.resolve('less-loader') // compiles Less to CSS
}
]