类的装饰器
- 只有类、类的方法、类的属性才有装饰器。普通的方法、没有装饰器(函数存在变量提升。类不存在。方法用了装饰器会报错:Leading decorators must be attached to a class declaration)
- 装饰器的作用是:扩充类的功能和属性。
- 使用类的装饰器,需要安装
npm install --save-dev @babel/plugin-proposal-decorators
配置package.json
"babel": {
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
]
],
"presets": [
"react-app"
]
},
ps:关于变量提升。var、function有变量提升。var提升的只是声明,函数提升的是整个方法体。
es6的class let const都没有。都有。只不过 只提升声明,不提升定义。因此不可以先试用 后定义
运行原理
// connect
class App extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(App);
// 等同于
@connect(mapStateToProps, mapDispatchToProps)
export default class App extends React.Component {}
// Form.create
const WrappedApp = Form.create()(App);
// 等同于
@Form.create()
class App extends React.Component {}
几种场景
1、给类添加静态属性
// 1、只改变目标类的某个静态属性
function deco1(target) {
target.age = '10--20'
}
@deco1
class MainFun {
constructor(name) {
this.name = name
}
work() {
console.log(this.name + ' coding')
}
}
let main = new MainFun('main')
main.work()
console.log(main)
console.log(MainFun.age)

2、 带参传递,并给静态类加一个实例属性(通过原型链继承)
// 2、带参传递,并给静态类加一个实例属性(通过原型链继承)
function deco2(address) {
return function (target) {
target.prototype.address = address
}
}
@deco1
@deco2('火星路')
class MainFun {
constructor(name) {
this.name = name
}
work() {
console.log(this.name + ' coding')
}
}

3、直接改变当前类的 只返回一个 string(正常人用不到的特殊情况)
此时就不能new MainFun 了
分析前3个案例可以看出: 装饰器return 什么, target就会变成什么。不return,就只是修改或者获取target。(这里的return 是针对最里层的function的return而言)
// 3、直接改变当前类的 只返回一个 string
function deco3(str) {
return function (target) {
return str
}
}
@deco3('太热了')
class MainFun {
constructor(name) {
this.name = name
}
work() {
console.log(this.name + ' coding')
}
}
console.log(MainFun)

4、类方法的装饰器
类方法(或属性)的装饰器的有3个参数,分别是:类的定义、属性/方法/实例访问器属性名、属性操作符
function deco4(time) {
console.log('time' + time)
return function (...rest) {
rest.forEach((arg, index) => {
console.log(`参数${index}`, arg)
})
console.log('****************')
}
}
class MainFun {
constructor(name) {
this.name = name
}
@deco4('2022-8-2')
work() {
console.log(this.name + ' coding')
}
}
let main = new MainFun('main')
main.work()


5、高阶组件
react 里使用高阶组件,其实也是装饰器的一种体现。
核心就是:传入一个组件。对其添加方法和属性。然后再传出一个组件。
我们常用的 react-redux的connect就是个高阶组件、 withRouter也是,都是给被包裹的组件提供了一些方法和props。
同时,可以利用 recompact.compose。实现多个高阶组件的嵌套与合并
funca是我自定义的一个方法。用于给接入的组件添加一个name的props
import React from 'react'
const funca = Component => {
//此处return的是class Wc 那么原来用的Component也会变成 class Wc
return class Wc extends React.PureComponent {
render() {
return <Component name={12345} {...this.props} />
}
}
}
export default funca
下面代码里connect、withRouter是常见的高阶组件的入口函数。funca是我自定义的测试函数。
loginCheck里则有比较复杂的登录验证的逻辑。
由次可以看出recompact.compose可以帮助实现 @的作用。不用传入被包裹的组件,就能给当前组件添加一些想要的内容和逻辑
import recompact from 'recompact'
import funca from './test'
const enhance = recompact.compose(
connect(state => ({ loginRedux: state.loginRedux }), { loginOut }),
withRouter,
loginCheck('main/Show'),
funca
)
@enhance
class ShowMap extends React.Component {
constructor(props) {
super(props)
this.state = {}
}
componentDidMount() {
console.log(this.props)
}
render() {
return <section id={styles.ShowMap}>地图</section>
}
}
export default ShowMap
我们再详细看loginCheck
userName = window.sessionStorage.getItem(‘userName’)根据这个判断是否已经登录。如果是已经登录则跳转到主页面。如果没登录,则跳到登录页面
/* eslint-disable arrow-body-style */
import React from 'react'
import { Redirect } from 'react-router-dom'
import { is, fromJS } from 'immutable'
/* 登陆验证 */
const LoginCheck = instance => Component => {
return class WrappedComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return (
!is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
)
}
render() {
const props = {
...this.props
}
const { location, loginRedux } = props
const { url } = loginRedux
const { pathname } = location
const userName = window.sessionStorage.getItem('userName')
let redirectUrl = ''
// 登录组件 登录成功后跳转至主页面'/index'
if (instance === 'login') {
redirectUrl = url && url !== pathname ? url : ''
}
// 主页面
if (instance === 'main/Show') {
redirectUrl = userName ? '' : url || '/login'
}
return (
<>
{redirectUrl ? <Redirect to={redirectUrl} /> : ''}
{instance === 'main/Show' && !userName ? null : <Component {...props} />}
</>
)
}
}
}
export default LoginCheck
装饰器参考:https://juejin.cn/post/7072883925764276254#heading-16
本文介绍了如何在JavaScript中使用类装饰器来扩充功能、添加静态属性和实例属性,以及在React中实现高阶组件的应用。通过实例演示了装饰器在不同场景下的使用,包括带参数的装饰器和类方法装饰器。
1413

被折叠的 条评论
为什么被折叠?



