React笔记(六)
前言
eg:代表代码对照 若文章有误,欢迎读者留言反馈传送门
问题:在项目中某些情况下,子元素样式会受父元素样式的影响
传送门作用:让当前元素逃离父元素,去想去的地方【一般是body】
使用场景:
- overflow: hidden
- 父组件z - index值太小,逃离父组件
- fixed需要放在body第一层级
- loading 弹框 全局组件 也应该放在最外面
1 | class PortalDemo extends Component { |
React中的Axios
Axios
发请求
react
中通过npm来安装axios
插件npm i -S axios
- 引入`axios包
挂载后,发送请求【组件渲染完成就开始发送请求,将请求到的数据渲染】
get方法请求[第一参数为请求接口地址,第二参数为对象,param形参名随意设定,但是里面params固定,简写{ params: id: 11, name: ‘aa’ }]
1 | // 语法格式: |
post方法请求[第一参数为请求接口地址,第二参数为对象,简写{ firstName: ‘black’ }]
1 | // 语法格式: |
对象写法【常规写法】
1 | // get方式 |
post方式也能使用params,拼接到url后面,具体原因分析:http://www.qianduanheidong.com/blog/article/319066/b5ef11c3754262a378ec/
eg1:
1 | import React, { Component } from 'react' |
post方式也能使用params,拼接到url后面,具体原因分析:http://www.qianduanheidong.com/blog/article/319066/b5ef11c3754262a378ec/
反向代理
反向代理用途:解决浏览器跨域问题
同源策略 http://localhost:8080 请求 https://api.i-lynn.cn/ip 协议域名端口号有一个不同就报跨域错误。
如何解决跨域:
- 前端: 反向代理
- 后端:
cors
反向代理- 服务器:
linux
正向 反向代理
React
的反向代理
- 安装代理插件
npm i -S http-proxy-middleware
- 在
src
目录下,创建一个setupProxy.js
文件【该文件不需要引入到哪里,配置完就可以使用了】- 开始配置反向代理
setupProxy.js文件配置代码如下[可以配置多个代理,例如/bpi]:
1 | const { createProxyMiddleware: proxy } = require('http-proxy-middleware') |
如何使用[以get为例]:
1 | componentDidMount(){ |
没做反向代理前
做了反向代理后
异步组件
- 异步引入组件[执行时不加载,需要用到的时候加载]
1 | const Child = React.lazy(() => import('./Child')) |
- 对比一下vue异步组件
1 | components: { Child: () => import('./Child') } |
- 异步组件使用[使用React.Suspense标签包裹异步组件标签占位符]
fallback属性可选,fallback是异步引入的loading销毁,fallback可以放一些loading好看的效果,刷新几下可以看到效果
1 | <React.Suspense fallback={<h2>------loading--------</h2>}> |
- 对比同步组件[直接使用]
1 | // 同步组件使用 |
SCU性能优化
shouldComponentUpdate(简称SCU)
react里面父组件刷新,他所有子组件都会自动刷新,SCU可以解决某个子组件依赖数据不发生变化,而对其不刷新
SCU 一定要每次都用吗?—— 需要的时候才优化,没有特殊要求,可以先完成功能为主,后期再优化
num的变化,当前组件要刷新,但是Child组件依赖数据没有变化,所以Child组件可以不用刷新,性能提升的点。
模拟场景:父组件里放一个num、arr,当我们更改num,父组件更新子组件无条件更新,而子组件依赖于arr,我们对子组件做性能优化(让其不更新):
1 | // 父组件 |
我们要对
Child1
子组件做SCU
,性能优化,this.props.arr
数组没有改变,Child1
组件中的render
就不用执行。
- 需要用到
shouldComponentUpdate(nextProps, nextState)
SCU
是render
的开关,默认返回是true
,默认情况下render
是要被渲染的。nextProps
是最新的props
,并不等于this.props
,所以我们可以判断nextProps
和this.props
是否相等就可以判断出数据有没有变化。nextState
就是最新state
.并不等于this.state
这两个也可以进行SCU的比较。
1 | // 子组件 |
上面只是浅比较,深比较【递归,借助第三方模块】
- 安装插件:
npm i -S lodash
- 子组件需要做
SCU
引入import _ from 'lodash'
lodash
工具类_.isEqual(obj1,obj2)
递归比较对象的值是否相等 相等返回true
1 | // 父组件 |
1 | // 子组件 |
类组件还自带一个浅比较的SCU,继承
PureComponent
来实现
1 | // 父组件 |
1 | // 子组件【注意引入的是PureComponent】 |
函数组件可以使用memo高阶组件来实现浅比较的SCU
1 | // 父组件 |
1 | // 子组件【注意引入的是高阶组件memo】 |
函数组件的深比较
1 | // 父组件 |
1 | import React, { memo } from 'react' |
SCU小结:
- 类组件自带一个浅比较继承自
PureComponent
,不需要我们去做判断,同时如果对象只有一层我们也可以使用shouldComponentUpdate
直接使用===
比较,深比较依旧是可以借助递归或工具类lodash
- 函数组件需要通过
memo
高阶组件来进行浅比较,不需要我们去做判断,深比较需要借助memo
高阶组件和lodash
HOC高阶组件【函数组件】
- 高阶组件一般是函数组件,参数是组件,返回值也还是一个组件。
- 高阶组件是为了提取公共功能用的,公共逻辑。高阶组件写越得越多说明能力越强,质量越高。
- 封装高阶组件,创建函数组件,传入一个组件作为参数,return一个类组件,这个类组件相当于穿插到了父子组件之间
- 使用:引入高阶组件,把高阶组件当函数用就行了【哪个组件需要这个高阶组件功能就往哪里引入,调用】
父组件
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 Child from './Child'
class HOCDemo extends Component {
state = {
arr: [1, 2, 3, 4, 5]
}
render() {
return (
<div>
<h3>父组件</h3>
<Child arr={this.state.arr} />
</div>
)
}
}
export default HOCDemo开始封装高阶组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import React, { Component } from 'react'
// hoc 高阶组件
// 高阶组件一般是函数组件,把组件作为参数传递进去,返回值还是一个组件
// 高阶组件是为了提取公共功能、公共逻辑用的。高阶组件写越多说明能力越强,质量越高。
// 1. 封装高阶组件,创建函数组件,传入一个组件作为参数,return一个类组件,这个类组件相当于穿插到了父子组件之间
// 2. 使用:引入高阶组件,把高阶组件当函数用就行了【哪个组件需要这个高阶组件功能就往哪里引入,调用】
const HOC = (COM) => {
return class newCom extends Component {
render() {
return (
<div>
{/* {...this.props} 承上启下 高阶组件必须携带,否则出现父子通信中断的bug */}
<COM {...this.props}/>
</div>
)
}
}
}
export default HOC子组件调用高阶组件
1 | import React, { Component } from 'react' |
开启装饰器模式,使用高阶组件语法糖@
装饰器模式的配置步骤:
配置装饰器支持
在当前项目根目录下面创建一个名称为config-overrides.js文件,对webpack进行配置1
2
3
4
5
6
7
8
9
10
11// react 配置文件
const path = require("path")
const {override,addDecoratorsLegacy,disableEsLint,addWebpackAlias} = require("customize-cra")
// 配置项 覆盖webpack某些配置
module.exports = override(
disableEsLint(), // 在webpack中禁用eslint
addDecoratorsLegacy(), // 开启装饰器
addWebpackAlias({ // 路径别名配置
["@"]: path.resolve(__dirname, "./src"),
})
)npm i -D customize-cra react-app-rewired
- 到package.json中的script命令中修改”start”: “react-app-rewired start”
会出现的bug:
对装饰器的实验支持功能在将来的版本中可能更改。在 “tsconfig” 或 “jsconfig” 中设置 “experimentalDecorators” 选项以删除此警告。ts(1219)(https://www.cnblogs.com/Annely/p/14613567.html)
- npm i @babel/plugin-proposal-decorators -D
- 项目根目录下创建babel.config.js 或者 .babelrc.js,复制粘贴如下代码:
1
2
3
4
5
6
7
8module.exports = {
presets: [
["@babel/preset-env"], // ES语法转换
],
plugins: [
['@babel/plugin-proposal-decorators', { 'legacy': true }]
]
}; vscode
的设置里搜索Experimental Decorators
打勾如下图
开启装饰器之后,使用语法糖: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// 高阶组件语法糖
import React, { Component } from 'react'
// 引入高阶组件
import HOC from './HOC'
// 装饰器模式 语法糖
// 调用高阶组件
@HOC
class Child extends Component {
render() {
return (
<div>
<h3>子组件</h3>
<ul>
{
this.props.arr.map((item, index) => {
return <li key={index}>{item}</li>
})
}
</ul>
</div>
)
}
}
export default HOC(Child)