# 起步
npm i -g create-react-app
1
create-react-app demo
1
项目启动如果报错,关闭dev-tools
reportWebVitals
:用来分析网页性能的库
React.StrictMode
:用来规范React写法的,因为React每个版本都有很多新的API不被推荐了,所以用一个严格模式进行写法限制
- 当前浏览器环境不支持js代码会展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<noscript>呵呵,垃圾浏览器,连js都不支持!</noscript>
</head>
<body>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- vscode语法提示:ES7+ React/Redux/React-Native snippets
- uuid:生成唯一序列码
# 使用hook
- 函数式组件,需要使用useState/useRef/useEffect来填补没有this/生命周期的缺陷。
- 同时,也可以利用hook将数据及操作数据的方法进行封装,暴露出对应的数据及方法,在组件内直接调用,组件代码更清晰。
export default function TodoList() {
const {
jobs,
addJob,
deleteJob,
toggleDone,
clear
} = useJobs();
return (
<div>
<Add addJob={addJob} />
<List jobs={jobs} deleteJob={deleteJob} toggleDone={toggleDone}/>
<Footer clear={clear} jobs={jobs}/>
</div>
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { useState } from 'react';
function useJobs() {
const [jobs, setJobs] = useState([])
const addJob = (job) => {
const item = {
id: uuid(),
done: false,
job
}
setJobs( [item, ...jobs] );
}
const deleteJob = (id) => {
const newJobs = jobs.filter(item => item.id !== id);
setJobs(newJobs);
}
const toggleDone = (id) => {
const newJobs = jobs.map(item => {
if (item.id === id) {
item.done = !item.done;
}
return item;
})
setJobs(newJobs);
}
const clear = () => setJobs([]);
return {
jobs,
addJob,
deleteJob,
toggleDone,
clear
}
}
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
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
# 跨域
- 文档 (opens new window)
- 在src同级目录下配置setupProxy.js文件
- app.use可以接收多个proxy代理
const proxy = require('http-proxy-middleware')
module.exports = function(app) {
app.use(
proxy.createProxyMiddleware('/api1', {
target: 'http://localhost:8888',
changeOrigin: true,
pathRewrite: {'^/api1': ''}
})
)
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 开头用指定好的url开头段,就会进行node代理发送
import React, { Component } from 'react'
export default class TodoList extends Component {
componentDidMount() {
console.log('fetch...');
fetch('/api1/info', {
method: 'GET'
}).then(res => res.json())
.then(res => console.log(res));
}
render() {
return (
<div>TodoList</div>
)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 请求源服务器资源不存在时,再转发请求
- 劣势:只能配置一个跨域服务器,有多个跨域服务器就要用setupProxy
"proxy": "http://localhost:8888"
1
- 对应请求
fetch('/info', {
method: 'GET'
}).then(res => res.json())
.then(res => console.log(res));
1
2
3
4
2
3
4
react-scripts模块中从2开始改变了proxy的配置方式,只能使用字符串配置,要复杂配置就用setupProxy
# pubsub
npm i pubsub-js
1
- 订阅
注:有一个多余参数,是本事件的type
import PubSub from "pubsub-js";
const [isLoading, setIsLoading] = useState(false);
PubSub.subscribe('setIsLoading', (_, state) => setIsLoading(state));
1
2
3
4
2
3
4
const [data, setData] = useState([]);
const searchData = (_, tip) => {
PubSub.publish('setIsLoading', true);
fetch(`/api/search/users?q=${tip}`)
.then(res => res.json())
.then(res => {
PubSub.publish('setIsLoading', false);
setData(res.items)
})
.catch(rea => PubSub.publish('setIsErr', true))
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
const token = PubSub.subscribe('setIsLoading', fn);
PubSub.unsubscribe(token);
1
2
2
import React, { useState, useEffect } from 'react';
import PubSub from 'pubsub-js';
export default function Test() {
const [count, setCount] = useState(0);
useEffect(() => {
const token = PubSub.subscribe('addOne', () => setCount(n => n + 1));
return () => PubSub.unsubscribe(token);
}, []);
return (
<>
<div>count: {count}</div>
<B />
</>
)
}
function B() {
return (<C />)
}
function C() {
const addOne = () => PubSub.publish('addOne');
return (
<>
<button onClick={addOne}>+1</button>
</>
)
}
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
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
# antd
文档不够完整可以看3.x版本的文档
// app.js
import 'antd/dist/antd.css';
1
2
2
- 组件内直接引入使用
import React from 'react'
import { Button } from 'antd';
export default function Test() {
return (
<>
<Button type="primary">Primary Button</Button>
<Button>Default Button</Button>
<Button type="dashed">Dashed Button</Button>
<br />
<Button type="text">Text Button</Button>
<Button type="link">Link Button</Button>
</>
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- css原本还是全部引入,有60KB,按序引入可以减少项目大小
- react-app-rewired (opens new window)
- 按需引入库:[ babel-plugin-import]
npm i react-app-rewired customize-cra babel-plugin-import
1
// package.json
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
}
1
2
3
4
5
6
2
3
4
5
6
// config-overrides.js
const { override, fixBabelImports } = require('customize-cra');
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
}),
);
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 组件引入
import { Button } from 'antd';
1
- 自定义主题暂时不能按需加载css文件
npm i @craco/craco craco-less
1
// craco.config.js
const CracoLessPlugin = require('craco-less');
module.exports = {
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
modifyVars: { '@primary-color': '#1DA57A' },
javascriptEnabled: true,
},
},
},
},
],
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// index.js
import 'antd/dist/antd.less';
1
2
2
# antd mobile
npm install --save antd-mobile@next
1
import React from 'react'
import { Button } from 'antd-mobile';
export default function Test() {
return (
<>
<Button block color='primary' size='large'>
Block Button
</Button>
</>
)
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
/* index.css */
:root:root {
--adm-color-primary: #a062d4;
}
1
2
3
4
2
3
4
// index.js
import './index.css';
1
2
2
# 样式适配
- pm2rem
npm i postcss-px2rem customize-cra react-app-rewired
1
// config-overrides.js
const { override, addPostcssPlugins } = require('customize-cra');
module.exports = override(
addPostcssPlugins([require('postcss-px2rem')({ remUnit: 375 / 10 })])
);
1
2
3
4
5
2
3
4
5
// package.json
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test"
},
1
2
3
4
5
6
2
3
4
5
6
- 通过计算文档宽度,得出根文件的font-size,从而控制整个文件的rem大小
function adaptor() {
const width = document.documentElement.clientWidth;
const size = width / 10;
document.documentElement.style.fontSize = size + 'px';
}
adaptor()
window.onresize = adaptor;
1
2
3
4
5
6
7
2
3
4
5
6
7
/* reset.css */
html,
body,
p,
ol,
ul,
li,
dl,
dt,
dd,
blockquote,
figure,
fieldset,
legend,
textarea,
pre,
iframe,
hr,
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
padding: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: 100%;
font-weight: normal;
}
ul {
list-style: none;
}
button,
input,
select {
margin: 0;
}
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
img,
video {
height: auto;
max-width: 100%;
}
iframe {
border: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75