js 类的装饰器 @ 和 react的高阶组件

本文介绍了如何在JavaScript中使用类装饰器来扩充功能、添加静态属性和实例属性,以及在React中实现高阶组件的应用。通过实例演示了装饰器在不同场景下的使用,包括带参数的装饰器和类方法装饰器。

类的装饰器

  1. 只有类、类的方法、类的属性才有装饰器。普通的方法、没有装饰器(函数存在变量提升。类不存在。方法用了装饰器会报错:Leading decorators must be attached to a class declaration
  2. 装饰器的作用是:扩充类的功能和属性。
  3. 使用类的装饰器,需要安装
    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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值